Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08e1b4d116 | ||
|
|
683580861f | ||
|
|
7d30460214 | ||
|
|
d7ba3291ed | ||
|
|
c07f54f370 | ||
|
|
6fe8ada37a | ||
|
|
94b10b5779 | ||
|
|
9b677c81a5 | ||
|
|
a25be61e94 | ||
|
|
116e00c21c | ||
|
|
122b0775f1 | ||
|
|
11f840b1e3 | ||
|
|
36039ddbb7 | ||
|
|
5347f0d583 | ||
|
|
408dde533f | ||
|
|
b15b46a68e | ||
|
|
ba6f298618 | ||
|
|
c6424921a6 | ||
|
|
8547802904 | ||
|
|
353e27b9e2 | ||
|
|
4a38a36036 | ||
|
|
200d2df785 | ||
|
|
73552c86c3 | ||
|
|
dd80e1f463 | ||
|
|
15c929a0e4 | ||
|
|
aa4c79cd9c | ||
|
|
6719abec65 | ||
|
|
79b9e07ee9 |
3
Makefile
3
Makefile
@@ -58,6 +58,7 @@ dist-no-debug: all
|
|||||||
mkdir atmosphere-$(AMSVER)/switch
|
mkdir atmosphere-$(AMSVER)/switch
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008
|
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000000D
|
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/0100000000000032
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034
|
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034
|
||||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036
|
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 -r config_templates/hbl_html atmosphere-$(AMSVER)/atmosphere/hbl_html
|
||||||
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000008/exefs.nsp
|
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/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/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/fatal/fatal.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000034/exefs.nsp
|
||||||
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036/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/ro/ro.elf atmosphere-$(AMSVER)-debug/ro.elf
|
||||||
cp stratosphere/sm/sm.elf atmosphere-$(AMSVER)-debug/sm.elf
|
cp stratosphere/sm/sm.elf atmosphere-$(AMSVER)-debug/sm.elf
|
||||||
cp stratosphere/spl/spl.elf atmosphere-$(AMSVER)-debug/spl.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 ../;
|
cd atmosphere-$(AMSVER)-debug; zip -r ../atmosphere-$(AMSVER)-debug.zip ./*; cd ../;
|
||||||
rm -r atmosphere-$(AMSVER)-debug
|
rm -r atmosphere-$(AMSVER)-debug
|
||||||
mv atmosphere-$(AMSVER)-debug.zip out/atmosphere-$(AMSVER)-debug.zip
|
mv atmosphere-$(AMSVER)-debug.zip out/atmosphere-$(AMSVER)-debug.zip
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,27 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
## 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
|
## 0.10.5
|
||||||
+ Changes were made to the way fs.mitm builds images when providing a layeredfs romfs.
|
+ 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.
|
+ Building romfs metadata previously had a memory cost of about ~4-5x the file table size.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/m4xw/emuMMC
|
remote = https://github.com/m4xw/emuMMC
|
||||||
branch = develop
|
branch = develop
|
||||||
commit = d12dd5464422029a1e5601916517ec3f1c81d8d0
|
commit = b168ddf5fbb31013ff529a4859110c82b11eb361
|
||||||
parent = 259a1a7513236a1de4d373bc6cb99032ede2c626
|
parent = c07f54f3709a4710e0aead6c91139fa0893b5e5c
|
||||||
method = rebase
|
method = rebase
|
||||||
cmdver = 0.4.1
|
cmdver = 0.4.1
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
||||||
|
|
||||||
### Supported Horizon Versions
|
### Supported Horizon Versions
|
||||||
**1.0.0 - 9.1.0**
|
**1.0.0 - 10.0.0**
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Arbitrary SDMMC backend selection
|
* Arbitrary SDMMC backend selection
|
||||||
|
|||||||
@@ -45,6 +45,8 @@
|
|||||||
#include "offsets/900_exfat.h"
|
#include "offsets/900_exfat.h"
|
||||||
#include "offsets/910.h"
|
#include "offsets/910.h"
|
||||||
#include "offsets/910_exfat.h"
|
#include "offsets/910_exfat.h"
|
||||||
|
#include "offsets/1000.h"
|
||||||
|
#include "offsets/1000_exfat.h"
|
||||||
#include "../utils/fatal.h"
|
#include "../utils/fatal.h"
|
||||||
|
|
||||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
#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(_900_EXFAT);
|
||||||
DEFINE_OFFSET_STRUCT(_910);
|
DEFINE_OFFSET_STRUCT(_910);
|
||||||
DEFINE_OFFSET_STRUCT(_910_EXFAT);
|
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) {
|
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
@@ -161,6 +165,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
|||||||
return &(GET_OFFSET_STRUCT_NAME(_910));
|
return &(GET_OFFSET_STRUCT_NAME(_910));
|
||||||
case FS_VER_9_1_0_EXFAT:
|
case FS_VER_9_1_0_EXFAT:
|
||||||
return &(GET_OFFSET_STRUCT_NAME(_910_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:
|
default:
|
||||||
fatal_abort(Fatal_UnknownVersion);
|
fatal_abort(Fatal_UnknownVersion);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ enum FS_VER
|
|||||||
FS_VER_9_1_0,
|
FS_VER_9_1_0,
|
||||||
FS_VER_9_1_0_EXFAT,
|
FS_VER_9_1_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_10_0_0,
|
||||||
|
FS_VER_10_0_0_EXFAT,
|
||||||
|
|
||||||
FS_VER_MAX,
|
FS_VER_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
58
emummc/source/FS/offsets/1000.h
Normal file
58
emummc/source/FS/offsets/1000.h
Normal 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__
|
||||||
58
emummc/source/FS/offsets/1000_exfat.h
Normal file
58
emummc/source/FS/offsets/1000_exfat.h
Normal 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__
|
||||||
@@ -36,7 +36,6 @@ sdmmc_storage_t sd_storage;
|
|||||||
|
|
||||||
// init vars
|
// init vars
|
||||||
bool custom_driver = true;
|
bool custom_driver = true;
|
||||||
extern const volatile emuMMC_ctx_t emuMMC_ctx;
|
|
||||||
|
|
||||||
// FS funcs
|
// FS funcs
|
||||||
_sdmmc_accessor_gc sdmmc_accessor_gc;
|
_sdmmc_accessor_gc sdmmc_accessor_gc;
|
||||||
@@ -344,7 +343,7 @@ uint64_t sdmmc_wrapper_controller_close(int mmc_id)
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mmc_id == FS_SDMMC_EMMC)
|
if (mmc_id == FS_SDMMC_EMMC)
|
||||||
{
|
{
|
||||||
// Close file handles and unmount
|
// Close file handles and unmount
|
||||||
|
|||||||
@@ -50,8 +50,18 @@ extern "C" {
|
|||||||
* @return Result code.
|
* @return Result code.
|
||||||
* @note Syscall number 0x55.
|
* @note Syscall number 0x55.
|
||||||
* @warning This is a privileged syscall. Use \ref envIsSyscallHinted to check if it is available.
|
* @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.
|
* @brief Attaches a device address space to a device.
|
||||||
|
|||||||
@@ -17,6 +17,15 @@
|
|||||||
.endm
|
.endm
|
||||||
|
|
||||||
SVC_BEGIN svcQueryIoMapping
|
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]!
|
STR X0, [SP, #-16]!
|
||||||
SVC 0x55
|
SVC 0x55
|
||||||
LDR X2, [SP], #16
|
LDR X2, [SP], #16
|
||||||
|
|||||||
@@ -25,11 +25,12 @@ enum FatalReason
|
|||||||
Fatal_InvalidAccessor,
|
Fatal_InvalidAccessor,
|
||||||
Fatal_ReadNoAccessor,
|
Fatal_ReadNoAccessor,
|
||||||
Fatal_WriteNoAccessor,
|
Fatal_WriteNoAccessor,
|
||||||
Fatal_IoMapping,
|
Fatal_IoMappingLegacy,
|
||||||
Fatal_UnknownVersion,
|
Fatal_UnknownVersion,
|
||||||
Fatal_BadResult,
|
Fatal_BadResult,
|
||||||
Fatal_GetConfig,
|
Fatal_GetConfig,
|
||||||
Fatal_CloseAccessor,
|
Fatal_CloseAccessor,
|
||||||
|
Fatal_IoMapping,
|
||||||
Fatal_Max
|
Fatal_Max
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,15 @@ static inline uintptr_t _GetIoMapping(u64 io_addr, u64 io_size)
|
|||||||
u64 vaddr;
|
u64 vaddr;
|
||||||
u64 aligned_addr = (io_addr & ~0xFFFul);
|
u64 aligned_addr = (io_addr & ~0xFFFul);
|
||||||
u64 aligned_size = io_size + (io_addr - aligned_addr);
|
u64 aligned_size = io_size + (io_addr - aligned_addr);
|
||||||
if (svcQueryIoMapping(&vaddr, aligned_addr, aligned_size) != 0) {
|
if (emuMMC_ctx.fs_ver >= FS_VER_10_0_0) {
|
||||||
fatal_abort(Fatal_IoMapping);
|
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));
|
return (uintptr_t)(vaddr + (io_addr - aligned_addr));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#define _UTIL_H_
|
#define _UTIL_H_
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "../emuMMC/emummc_ctx.h"
|
||||||
|
|
||||||
intptr_t QueryIoMapping(u64 addr, u64 size);
|
intptr_t QueryIoMapping(u64 addr, u64 size);
|
||||||
#define byte_swap_32(num) ((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
|
#define byte_swap_32(num) ((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | \
|
||||||
@@ -37,4 +38,6 @@ void usleep(u64 ticks);
|
|||||||
void msleep(u64 milliseconds);
|
void msleep(u64 milliseconds);
|
||||||
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
|
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
|
||||||
|
|
||||||
|
extern volatile emuMMC_ctx_t emuMMC_ctx;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -263,19 +263,20 @@ uint32_t fuse_get_5x_key_generation(void) {
|
|||||||
/* Returns the fuse version expected for the firmware. */
|
/* Returns the fuse version expected for the firmware. */
|
||||||
uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware) {
|
uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware) {
|
||||||
static const uint8_t expected_versions[ATMOSPHERE_TARGET_FIRMWARE_COUNT+1] = {
|
static const uint8_t expected_versions[ATMOSPHERE_TARGET_FIRMWARE_COUNT+1] = {
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_100] = 1,
|
[ATMOSPHERE_TARGET_FIRMWARE_100] = 1,
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_200] = 2,
|
[ATMOSPHERE_TARGET_FIRMWARE_200] = 2,
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_300] = 3,
|
[ATMOSPHERE_TARGET_FIRMWARE_300] = 3,
|
||||||
/* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */
|
/* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_400] = 5,
|
[ATMOSPHERE_TARGET_FIRMWARE_400] = 5,
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_500] = 6,
|
[ATMOSPHERE_TARGET_FIRMWARE_500] = 6,
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_600] = 7,
|
[ATMOSPHERE_TARGET_FIRMWARE_600] = 7,
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_620] = 8,
|
[ATMOSPHERE_TARGET_FIRMWARE_620] = 8,
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_700] = 9,
|
[ATMOSPHERE_TARGET_FIRMWARE_700] = 9,
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_800] = 9,
|
[ATMOSPHERE_TARGET_FIRMWARE_800] = 9,
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_810] = 10,
|
[ATMOSPHERE_TARGET_FIRMWARE_810] = 10,
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_900] = 11,
|
[ATMOSPHERE_TARGET_FIRMWARE_900] = 11,
|
||||||
[ATMOSPHERE_TARGET_FIRMWARE_910] = 12,
|
[ATMOSPHERE_TARGET_FIRMWARE_910] = 12,
|
||||||
|
[ATMOSPHERE_TARGET_FIRMWARE_1000] = 13,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (target_firmware > ATMOSPHERE_TARGET_FIRMWARE_COUNT) {
|
if (target_firmware > ATMOSPHERE_TARGET_FIRMWARE_COUNT) {
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ static void setup_se(void) {
|
|||||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_900:
|
case ATMOSPHERE_TARGET_FIRMWARE_900:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
||||||
|
case ATMOSPHERE_TARGET_FIRMWARE_1000:
|
||||||
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
|
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -338,7 +339,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
|
|||||||
|
|
||||||
/* Perform version checks. */
|
/* Perform version checks. */
|
||||||
/* We will be compatible with all package2s released before current, but not newer ones. */
|
/* 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,6 +467,7 @@ static void copy_warmboot_bin_to_dram() {
|
|||||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_900:
|
case ATMOSPHERE_TARGET_FIRMWARE_900:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
||||||
|
case ATMOSPHERE_TARGET_FIRMWARE_1000:
|
||||||
warmboot_src = (uint8_t *)0x4003E000;
|
warmboot_src = (uint8_t *)0x4003E000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -551,6 +553,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
|||||||
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
||||||
MAKE_REG32(PMC_BASE + 0x360) = 0x18C;
|
MAKE_REG32(PMC_BASE + 0x360) = 0x18C;
|
||||||
break;
|
break;
|
||||||
|
case ATMOSPHERE_TARGET_FIRMWARE_1000:
|
||||||
|
MAKE_REG32(PMC_BASE + 0x360) = 0x1AD;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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_700_800 0xA
|
||||||
#define PACKAGE2_MAXVER_810 0xB
|
#define PACKAGE2_MAXVER_810 0xB
|
||||||
#define PACKAGE2_MAXVER_900 0xC
|
#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_100 0x3
|
||||||
#define PACKAGE2_MINVER_200 0x4
|
#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_700_800 0xB
|
||||||
#define PACKAGE2_MINVER_810 0xC
|
#define PACKAGE2_MINVER_810 0xC
|
||||||
#define PACKAGE2_MINVER_900 0xD
|
#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 {
|
typedef struct {
|
||||||
union {
|
union {
|
||||||
|
|||||||
20
exosphere/src/rsa_common.c
Normal file
20
exosphere/src/rsa_common.c
Normal 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 = {};
|
||||||
36
exosphere/src/rsa_common.h
Normal file
36
exosphere/src/rsa_common.h
Normal 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
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "utils.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.address = 0;
|
||||||
ll->addr_info.size = 0;
|
ll->addr_info.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_dcache_range((uint8_t *)ll, (uint8_t *)ll + sizeof(*ll));
|
flush_dcache_range((uint8_t *)ll, (uint8_t *)ll + sizeof(*ll));
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_security_engine_callback(unsigned int (*callback)(void)) {
|
void set_security_engine_callback(unsigned int (*callback)(void)) {
|
||||||
if (callback == NULL || g_se_callback != NULL) {
|
/* Set the callback. */
|
||||||
generic_panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
g_se_callback = 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. */
|
/* Fires on Security Engine operation completion. */
|
||||||
void se_operation_completed(void) {
|
void se_operation_completed(void) {
|
||||||
se_get_regs()->SE_INT_ENABLE = 0;
|
se_get_regs()->SE_INT_ENABLE = 0;
|
||||||
if (g_se_callback != NULL) {
|
unsigned int (*callback)(void) = g_se_callback;
|
||||||
g_se_callback();
|
if (callback != NULL) {
|
||||||
g_se_callback = NULL;
|
g_se_callback = NULL;
|
||||||
|
callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +104,7 @@ void se_validate_stored_vector(void) {
|
|||||||
|
|
||||||
uint8_t calc_vector[0x10];
|
uint8_t calc_vector[0x10];
|
||||||
se_generate_test_vector(calc_vector);
|
se_generate_test_vector(calc_vector);
|
||||||
|
|
||||||
/* Ensure nobody's messed with the security engine while we slept. */
|
/* Ensure nobody's messed with the security engine while we slept. */
|
||||||
if (memcmp(calc_vector, g_se_stored_test_vector, 0x10) != 0) {
|
if (memcmp(calc_vector, g_se_stored_test_vector, 0x10) != 0) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
@@ -122,7 +123,7 @@ void se_generate_stored_vector(void) {
|
|||||||
/* Set the flags for an AES keyslot. */
|
/* Set the flags for an AES keyslot. */
|
||||||
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
@@ -141,7 +142,7 @@ void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
|||||||
/* Set the flags for an RSA keyslot. */
|
/* Set the flags for an RSA keyslot. */
|
||||||
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_RSA_MAX) {
|
if (keyslot >= KEYSLOT_RSA_MAX) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
@@ -160,7 +161,7 @@ void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
|||||||
|
|
||||||
void clear_aes_keyslot(unsigned int keyslot) {
|
void clear_aes_keyslot(unsigned int keyslot) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
@@ -174,7 +175,7 @@ void clear_aes_keyslot(unsigned int keyslot) {
|
|||||||
|
|
||||||
void clear_rsa_keyslot(unsigned int keyslot) {
|
void clear_rsa_keyslot(unsigned int keyslot) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_RSA_MAX) {
|
if (keyslot >= KEYSLOT_RSA_MAX) {
|
||||||
generic_panic();
|
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) {
|
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
|
if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
|
||||||
generic_panic();
|
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) {
|
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();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
|
if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
|
||||||
generic_panic();
|
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) {
|
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
|
if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
|
||||||
generic_panic();
|
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) {
|
void clear_aes_keyslot_iv(unsigned int keyslot) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||||
generic_panic();
|
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) {
|
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();
|
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) {
|
if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSIZE_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
|
||||||
generic_panic();
|
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)) {
|
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();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||||
generic_panic();
|
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 the callback, for after the async operation. */
|
||||||
set_security_engine_callback(callback);
|
set_security_engine_callback(callback);
|
||||||
|
|
||||||
/* Enable SE Interrupt firing for async op. */
|
|
||||||
se->SE_INT_ENABLE = 0x10;
|
|
||||||
|
|
||||||
/* Setup Input/Output lists */
|
/* Setup Input/Output lists */
|
||||||
se->SE_IN_LL_ADDR = in_ll_paddr;
|
se->SE_IN_LL_ADDR = in_ll_paddr;
|
||||||
se->SE_OUT_LL_ADDR = out_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);
|
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();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
uint8_t stack_buf[KEYSIZE_RSA_MAX];
|
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. */
|
/* Endian swap the input. */
|
||||||
for (size_t i = 0; i < size; i++) {
|
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);
|
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);
|
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);
|
flush_dcache_range(stack_buf, stack_buf + KEYSIZE_RSA_MAX);
|
||||||
trigger_se_rsa_op(stack_buf, size);
|
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) {
|
void trigger_se_rsa_op(void *buf, size_t size) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
se_ll_t in_ll;
|
se_ll_t in_ll;
|
||||||
|
|
||||||
ll_init(&in_ll, (void *)buf, size);
|
ll_init(&in_ll, (void *)buf, size);
|
||||||
|
|
||||||
/* Set the input LL. */
|
/* 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(&in_ll, (void *)src, src_size);
|
||||||
ll_init(&out_ll, dst, dst_size);
|
ll_init(&out_ll, dst, dst_size);
|
||||||
|
|
||||||
__dsb_sy();
|
__dsb_sy();
|
||||||
|
|
||||||
/* Set the LLs. */
|
/* Set the LLs. */
|
||||||
se->SE_IN_LL_ADDR = (uint32_t) get_physical_address(&in_ll);
|
se->SE_IN_LL_ADDR = (uint32_t) get_physical_address(&in_ll);
|
||||||
se->SE_OUT_LL_ADDR = (uint32_t) get_physical_address(&out_ll);
|
se->SE_OUT_LL_ADDR = (uint32_t) get_physical_address(&out_ll);
|
||||||
|
|
||||||
/* Set registers for operation. */
|
/* Set registers for operation. */
|
||||||
se->SE_ERR_STATUS = se->SE_ERR_STATUS;
|
se->SE_ERR_STATUS = se->SE_ERR_STATUS;
|
||||||
se->SE_INT_STATUS = se->SE_INT_STATUS;
|
se->SE_INT_STATUS = se->SE_INT_STATUS;
|
||||||
se->SE_OPERATION = op;
|
se->SE_OPERATION = op;
|
||||||
(void)(se->SE_OPERATION);
|
(void)(se->SE_OPERATION);
|
||||||
|
|
||||||
__dsb_ish();
|
__dsb_ish();
|
||||||
|
|
||||||
while (!(se->SE_INT_STATUS & 0x10)) { /* Wait a while */ }
|
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) {
|
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();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
|
if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
|
||||||
generic_panic();
|
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) {
|
if (dst_size) {
|
||||||
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
|
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int num_blocks = src_size >> 4;
|
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) {
|
if (dst_size) {
|
||||||
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + 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) {
|
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();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
||||||
generic_panic();
|
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) {
|
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();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
||||||
generic_panic();
|
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) {
|
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();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_size) {
|
if (data_size) {
|
||||||
flush_dcache_range((uint8_t *)data, (uint8_t *)data + 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. */
|
/* Generate the derived key, to be XOR'd with final output block. */
|
||||||
uint8_t derived_key[0x10] = {0};
|
uint8_t derived_key[0x10] = {0};
|
||||||
se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high);
|
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_CONFIG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
|
||||||
se->SE_CRYPTO_CONFIG = (keyslot << 24) | (0x145);
|
se->SE_CRYPTO_CONFIG = (keyslot << 24) | (0x145);
|
||||||
clear_aes_keyslot_iv(keyslot);
|
clear_aes_keyslot_iv(keyslot);
|
||||||
|
|
||||||
unsigned int num_blocks = (data_size + 0xF) >> 4;
|
unsigned int num_blocks = (data_size + 0xF) >> 4;
|
||||||
/* Handle aligned blocks. */
|
/* Handle aligned blocks. */
|
||||||
if (num_blocks > 1) {
|
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);
|
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
|
||||||
se->SE_CRYPTO_CONFIG |= 0x80;
|
se->SE_CRYPTO_CONFIG |= 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create final block. */
|
/* Create final block. */
|
||||||
uint8_t last_block[0x10] = {0};
|
uint8_t last_block[0x10] = {0};
|
||||||
if (data_size & 0xF) {
|
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) {
|
} else if (data_size >= 0x10) {
|
||||||
memcpy(last_block, data + data_size - 0x10, 0x10);
|
memcpy(last_block, data + data_size - 0x10, 0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 0x10; i++) {
|
for (unsigned int i = 0; i < 0x10; i++) {
|
||||||
last_block[i] ^= derived_key[i];
|
last_block[i] ^= derived_key[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform last operation. */
|
/* Perform last operation. */
|
||||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||||
flush_dcache_range(last_block, last_block + sizeof(last_block));
|
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) {
|
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();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
|
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
|
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
|
||||||
se->SE_CRYPTO_CONFIG = (keyslot << 24) | 0x144;
|
se->SE_CRYPTO_CONFIG = (keyslot << 24) | 0x144;
|
||||||
set_aes_keyslot_iv(keyslot, iv, 0x10);
|
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. */
|
/* SHA256 Implementation. */
|
||||||
void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
|
void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
/* Setup config for SHA256, size = BITS(src_size) */
|
/* Setup config for SHA256, size = BITS(src_size) */
|
||||||
se->SE_CONFIG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
|
se->SE_CONFIG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
|
||||||
se->SE_SHA_CONFIG = 1;
|
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[1] = 0;
|
||||||
se->SE_SHA_MSG_LEFT[2] = 0;
|
se->SE_SHA_MSG_LEFT[2] = 0;
|
||||||
se->SE_SHA_MSG_LEFT[3] = 0;
|
se->SE_SHA_MSG_LEFT[3] = 0;
|
||||||
|
|
||||||
/* Trigger the operation. */
|
/* Trigger the operation. */
|
||||||
trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);
|
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 */
|
/* RNG API */
|
||||||
void se_initialize_rng(unsigned int keyslot) {
|
void se_initialize_rng(unsigned int keyslot) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||||
generic_panic();
|
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) {
|
void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
@@ -777,7 +772,7 @@ void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
|
|||||||
/* SE context save API. */
|
/* SE context save API. */
|
||||||
void se_set_in_context_save_mode(bool is_context_save_mode) {
|
void se_set_in_context_save_mode(bool is_context_save_mode) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
uint32_t val = se->SE_SE_SECURITY;
|
uint32_t val = se->SE_SE_SECURITY;
|
||||||
if (is_context_save_mode) {
|
if (is_context_save_mode) {
|
||||||
val |= 0x10000;
|
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) {
|
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) {
|
if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) {
|
||||||
generic_panic();
|
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_CRYPTO_CONFIG = (rng_keyslot << 24) | 0x108;
|
||||||
se->SE_RNG_CONFIG = 4;
|
se->SE_RNG_CONFIG = 4;
|
||||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||||
|
|
||||||
/* Generate low part of key. */
|
/* Generate low part of key. */
|
||||||
se->SE_CRYPTO_KEYTABLE_DST = (dst_keyslot << 8);
|
se->SE_CRYPTO_KEYTABLE_DST = (dst_keyslot << 8);
|
||||||
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
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) {
|
void se_generate_srk(unsigned int srkgen_keyslot) {
|
||||||
volatile tegra_se_t *se = se_get_regs();
|
volatile tegra_se_t *se = se_get_regs();
|
||||||
|
|
||||||
se->SE_CONFIG = (ALG_RNG | DST_SRK);
|
se->SE_CONFIG = (ALG_RNG | DST_SRK);
|
||||||
se->SE_CRYPTO_CONFIG = (srkgen_keyslot << 24) | 0x108;
|
se->SE_CRYPTO_CONFIG = (srkgen_keyslot << 24) | 0x108;
|
||||||
se->SE_RNG_CONFIG = 6;
|
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). */
|
/* Generate the SRK (context save encryption key). */
|
||||||
se_generate_random_key(srkgen_keyslot, rng_keyslot);
|
se_generate_random_key(srkgen_keyslot, rng_keyslot);
|
||||||
se_generate_srk(srkgen_keyslot);
|
se_generate_srk(srkgen_keyslot);
|
||||||
|
|
||||||
flush_dcache_range(work_buf, work_buf + 0x10);
|
flush_dcache_range(work_buf, work_buf + 0x10);
|
||||||
se_generate_random(rng_keyslot, work_buf, 0x10);
|
se_generate_random(rng_keyslot, work_buf, 0x10);
|
||||||
flush_dcache_range(work_buf, work_buf + 0x10);
|
flush_dcache_range(work_buf, work_buf + 0x10);
|
||||||
|
|
||||||
/* Save random initial block. */
|
/* Save random initial block. */
|
||||||
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY);
|
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY);
|
||||||
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_MEM);
|
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_MEM);
|
||||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||||
se_encrypt_with_srk(dst, 0x10, work_buf, 0x10);
|
se_encrypt_with_srk(dst, 0x10, work_buf, 0x10);
|
||||||
|
|
||||||
/* Save Sticky Bits. */
|
/* Save Sticky Bits. */
|
||||||
for (unsigned int i = 0; i < 0x2; i++) {
|
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_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT);
|
||||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||||
se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0);
|
se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save AES Key Table. */
|
/* Save AES Key Table. */
|
||||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
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);
|
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->SE_CRYPTO_LAST_BLOCK = 0;
|
||||||
se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0);
|
se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save AES Original IVs. */
|
/* Save AES Original IVs. */
|
||||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
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_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->SE_CRYPTO_LAST_BLOCK = 0;
|
||||||
se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0);
|
se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save AES Updated IVs */
|
/* Save AES Updated IVs */
|
||||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
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_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->SE_CRYPTO_LAST_BLOCK = 0;
|
||||||
se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0);
|
se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save RSA Keytable. */
|
/* Save RSA Keytable. */
|
||||||
uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430;
|
uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430;
|
||||||
for (unsigned int rsa_key = 0; rsa_key < KEYSLOT_RSA_MAX; rsa_key++) {
|
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. " */
|
/* 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};
|
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_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_MEM);
|
||||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||||
se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10);
|
se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10);
|
||||||
|
|
||||||
/* Save SRK into PMC registers. */
|
/* Save SRK into PMC registers. */
|
||||||
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_SRK);
|
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_SRK);
|
||||||
se->SE_CRYPTO_LAST_BLOCK = 0;
|
se->SE_CRYPTO_LAST_BLOCK = 0;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef EXOSPHERE_SE_H
|
#ifndef EXOSPHERE_SE_H
|
||||||
#define 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);
|
void se_calculate_sha256(void *dst, const void *src, size_t src_size);
|
||||||
|
|
||||||
/* RSA API */
|
/* 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_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);
|
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);
|
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);
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ void set_version_specific_smcs(void) {
|
|||||||
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
case ATMOSPHERE_TARGET_FIRMWARE_810:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_900:
|
case ATMOSPHERE_TARGET_FIRMWARE_900:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
||||||
|
case ATMOSPHERE_TARGET_FIRMWARE_1000:
|
||||||
/* No more LoadSecureExpModKey. */
|
/* No more LoadSecureExpModKey. */
|
||||||
g_smc_user_table[0xE].handler = NULL;
|
g_smc_user_table[0xE].handler = NULL;
|
||||||
g_smc_user_table[0xC].id = 0xC300D60C;
|
g_smc_user_table[0xC].id = 0xC300D60C;
|
||||||
@@ -433,19 +434,18 @@ uint32_t smc_get_result(smc_args_t *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t smc_exp_mod_get_result(void *buf, uint64_t size) {
|
uint32_t smc_exp_mod_get_result(void *buf, uint64_t size) {
|
||||||
if (get_exp_mod_done() != 1) {
|
uint32_t res = get_exp_mod_result();
|
||||||
return 3;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t smc_exp_mod(smc_args_t *args) {
|
uint32_t smc_exp_mod(smc_args_t *args) {
|
||||||
@@ -508,30 +508,31 @@ uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey_get_result(void *buf, uint64_t siz
|
|||||||
uint8_t aes_wrapped_titlekey[0x10];
|
uint8_t aes_wrapped_titlekey[0x10];
|
||||||
uint8_t titlekey[0x10];
|
uint8_t titlekey[0x10];
|
||||||
uint64_t sealed_titlekey[2];
|
uint64_t sealed_titlekey[2];
|
||||||
if (get_exp_mod_done() != 1) {
|
uint32_t res = get_exp_mod_result();
|
||||||
return 3;
|
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 res;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
|
uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
|
||||||
|
|||||||
@@ -34,12 +34,93 @@
|
|||||||
|
|
||||||
/* Globals. */
|
/* Globals. */
|
||||||
static bool g_crypt_aes_done = false;
|
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 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) {
|
static bool is_user_keyslot_valid(unsigned int keyslot) {
|
||||||
switch (exosphere_get_target_firmware()) {
|
switch (exosphere_get_target_firmware()) {
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_100:
|
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_810:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_900:
|
case ATMOSPHERE_TARGET_FIRMWARE_900:
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
||||||
|
case ATMOSPHERE_TARGET_FIRMWARE_1000:
|
||||||
default:
|
default:
|
||||||
return keyslot <= 5;
|
return keyslot <= 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_exp_mod_done(bool done) {
|
void set_exp_mod_result(uint32_t result) {
|
||||||
g_exp_mod_done = done;
|
g_exp_mod_result = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_exp_mod_done(void) {
|
uint32_t get_exp_mod_result(void) {
|
||||||
return g_exp_mod_done;
|
return g_exp_mod_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t exp_mod_done_handler(void) {
|
uint32_t exp_mod_done_handler(void) {
|
||||||
set_exp_mod_done(true);
|
set_exp_mod_result(0);
|
||||||
|
|
||||||
se_trigger_interrupt();
|
se_trigger_interrupt();
|
||||||
|
|
||||||
return 0;
|
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) {
|
uint32_t user_exp_mod(smc_args_t *args) {
|
||||||
uint8_t modulus[0x100];
|
uint8_t modulus[0x100];
|
||||||
uint8_t exponent[0x100];
|
uint8_t exponent[0x100];
|
||||||
@@ -108,7 +207,8 @@ uint32_t user_exp_mod(smc_args_t *args) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_exp_mod_done(false);
|
set_exp_mod_result(3);
|
||||||
|
|
||||||
/* Hardcode RSA keyslot 0. */
|
/* Hardcode RSA keyslot 0. */
|
||||||
set_rsa_keyslot(0, modulus, 0x100, exponent, exponent_size);
|
set_rsa_keyslot(0, modulus, 0x100, exponent, exponent_size);
|
||||||
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
|
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;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_exp_mod_done(false);
|
set_exp_mod_result(3);
|
||||||
|
|
||||||
/* Hardcode RSA keyslot 0. */
|
/* Hardcode RSA keyslot 0. */
|
||||||
set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100);
|
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_1000) {
|
||||||
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -700,7 +811,7 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_exp_mod_done(false);
|
set_exp_mod_result(3);
|
||||||
|
|
||||||
/* Expected label_hash occupies args->X[3] to args->X[6]. */
|
/* Expected label_hash occupies args->X[3] to args->X[6]. */
|
||||||
tkey_set_expected_label_hash(&args->X[3]);
|
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;
|
unsigned int exponent_id;
|
||||||
|
bool import_modulus;
|
||||||
|
|
||||||
switch (usecase) {
|
switch (usecase) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -888,22 +1000,33 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
|
|||||||
return 0;
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
exponent_id = 1;
|
exponent_id = 1;
|
||||||
|
import_modulus = false;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
exponent_id = 0;
|
exponent_id = 0;
|
||||||
|
import_modulus = true;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
exponent_id = 2;
|
exponent_id = 2;
|
||||||
|
import_modulus = false;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
exponent_id = 3;
|
exponent_id = 3;
|
||||||
|
import_modulus = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
generic_panic();
|
generic_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy key to global. */
|
/* Modulus import isn't implemented on < 10.0.0. */
|
||||||
memcpy(g_imported_exponents[exponent_id], user_data, 0x100);
|
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;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef EXOSPHERE_SMC_USER_H
|
#ifndef EXOSPHERE_SMC_USER_H
|
||||||
#define 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);
|
void set_crypt_aes_done(bool done);
|
||||||
bool get_crypt_aes_done(void);
|
bool get_crypt_aes_done(void);
|
||||||
|
|
||||||
void set_exp_mod_done(bool done);
|
void set_exp_mod_result(uint32_t result);
|
||||||
bool get_exp_mod_done(void);
|
uint32_t get_exp_mod_result(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -25,14 +25,10 @@
|
|||||||
#include "masterkey.h"
|
#include "masterkey.h"
|
||||||
#include "se.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. */
|
/* Set the expected db prefix. */
|
||||||
void tkey_set_expected_label_hash(uint64_t *label_hash) {
|
void tkey_set_expected_label_hash(uint64_t *label_hash) {
|
||||||
for (unsigned int i = 0; i < 4; i++) {
|
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) {
|
if (master_key_rev >= MASTERKEY_REVISION_MAX) {
|
||||||
generic_panic();
|
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) {
|
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) {
|
void tkey_set_type(unsigned int type) {
|
||||||
tkey_validate_type(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 */
|
/* 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;
|
uint8_t *db = message + 0x21;
|
||||||
|
|
||||||
/* This will be passed to smc_unwrap_rsa_oaep_wrapped_titlekey. */
|
/* 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. */
|
/* Unmask the salt. */
|
||||||
calculate_mgf1_and_xor(salt, 0x20, db, 0xDF);
|
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) {
|
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();
|
generic_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate the appropriate titlekek into keyslot 9. */
|
/* Generate the appropriate titlekek into keyslot 9. */
|
||||||
unsigned int master_keyslot = mkey_get_keyslot(g_tkey_master_key_rev);
|
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_tkey_type], 0x10);
|
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. */
|
/* Unwrap the titlekey using the titlekek. */
|
||||||
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, dst, 0x10, src, 0x10);
|
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, dst, 0x10, src, 0x10);
|
||||||
|
|||||||
@@ -13,11 +13,12 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef EXOSPHERE_TITLEKEY_H
|
#ifndef EXOSPHERE_TITLEKEY_H
|
||||||
#define EXOSPHERE_TITLEKEY_H
|
#define EXOSPHERE_TITLEKEY_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "rsa_common.h"
|
||||||
|
|
||||||
#define TITLEKEY_TYPE_MAX 0x1
|
#define TITLEKEY_TYPE_MAX 0x1
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ typedef enum {
|
|||||||
FS_VER_9_1_0,
|
FS_VER_9_1_0,
|
||||||
FS_VER_9_1_0_EXFAT,
|
FS_VER_9_1_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_10_0_0,
|
||||||
|
FS_VER_10_0_0_EXFAT,
|
||||||
|
|
||||||
FS_VER_MAX,
|
FS_VER_MAX,
|
||||||
} emummc_fs_ver_t;
|
} emummc_fs_ver_t;
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
"\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 */
|
"\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) {
|
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) {
|
||||||
|
|||||||
@@ -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 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};
|
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 */
|
/* svcControlCodeMemory Patches */
|
||||||
/* b.eq -> nop */
|
/* 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(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(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(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(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(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(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(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(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(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(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. */
|
/* Hook Definitions. */
|
||||||
static const kernel_patch_t g_kernel_patches_100[] = {
|
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,
|
#define KERNEL_PATCHES(vers) .num_patches = sizeof(g_kernel_patches_##vers)/sizeof(kernel_patch_t), .patches = g_kernel_patches_##vers,
|
||||||
|
|
||||||
/* Kernel Infos. */
|
/* Kernel Infos. */
|
||||||
@@ -811,6 +897,15 @@ static const kernel_info_t g_kernel_infos[] = {
|
|||||||
.embedded_ini_ptr = 0x180,
|
.embedded_ini_ptr = 0x180,
|
||||||
.free_code_space_offset = 0x65780,
|
.free_code_space_offset = 0x65780,
|
||||||
KERNEL_PATCHES(900)
|
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;
|
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);
|
const kernel_info_t *kernel_info = get_kernel_info(_kernel, *kernel_size);
|
||||||
*out_ini1 = NULL;
|
*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));
|
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);
|
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. */
|
/* Update size. */
|
||||||
*kernel_size = kernel_ldr_offset + kernel_ldr_bin_size;
|
*kernel_size = kernel_ldr_offset + kernel_ldr_bin_size;
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,6 @@
|
|||||||
|
|
||||||
#include "utils.h"
|
#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
|
#endif
|
||||||
@@ -160,6 +160,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
|
|||||||
desired_keyblob = MASTERKEY_REVISION_900;
|
desired_keyblob = MASTERKEY_REVISION_900;
|
||||||
/* Fallthrough */
|
/* Fallthrough */
|
||||||
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
case ATMOSPHERE_TARGET_FIRMWARE_910:
|
||||||
|
case ATMOSPHERE_TARGET_FIRMWARE_1000:
|
||||||
desired_keyblob = MASTERKEY_REVISION_910_CURRENT;
|
desired_keyblob = MASTERKEY_REVISION_910_CURRENT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -232,6 +232,8 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
|||||||
return ATMOSPHERE_TARGET_FIRMWARE_900;
|
return ATMOSPHERE_TARGET_FIRMWARE_900;
|
||||||
} else if (memcmp(package1loader_header->build_timestamp, "20191021", 8) == 0) {
|
} else if (memcmp(package1loader_header->build_timestamp, "20191021", 8) == 0) {
|
||||||
return ATMOSPHERE_TARGET_FIRMWARE_910;
|
return ATMOSPHERE_TARGET_FIRMWARE_910;
|
||||||
|
} else if (memcmp(package1loader_header->build_timestamp, "20200303", 8) == 0) {
|
||||||
|
return ATMOSPHERE_TARGET_FIRMWARE_1000;
|
||||||
} else {
|
} else {
|
||||||
fatal_error("[NXBOOT] Unable to identify package1!\n");
|
fatal_error("[NXBOOT] Unable to identify package1!\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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. */
|
/* 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. */
|
/* 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) ||
|
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. */
|
/* Perform version checks. */
|
||||||
/* We will be compatible with all package2s released before current, but not newer ones. */
|
/* 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,8 @@
|
|||||||
#define PACKAGE2_MAXVER_700_800 0xA
|
#define PACKAGE2_MAXVER_700_800 0xA
|
||||||
#define PACKAGE2_MAXVER_810 0xB
|
#define PACKAGE2_MAXVER_810 0xB
|
||||||
#define PACKAGE2_MAXVER_900 0xC
|
#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_100 0x3
|
||||||
#define PACKAGE2_MINVER_200 0x4
|
#define PACKAGE2_MINVER_200 0x4
|
||||||
@@ -52,7 +53,8 @@
|
|||||||
#define PACKAGE2_MINVER_700_800 0xB
|
#define PACKAGE2_MINVER_700_800 0xB
|
||||||
#define PACKAGE2_MINVER_810 0xC
|
#define PACKAGE2_MINVER_810 0xC
|
||||||
#define PACKAGE2_MINVER_900 0xD
|
#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))
|
#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <mesosphere/kern_k_typed_address.hpp>
|
#include <mesosphere/kern_k_typed_address.hpp>
|
||||||
#include <mesosphere/kern_select_cpu.hpp>
|
#include <mesosphere/kern_select_cpu.hpp>
|
||||||
#include <mesosphere/arch/arm64/kern_k_page_table_entry.hpp>
|
#include <mesosphere/arch/arm64/kern_k_page_table_entry.hpp>
|
||||||
|
#include <mesosphere/kern_select_system_control.hpp>
|
||||||
|
|
||||||
namespace ams::kern::arch::arm64::init {
|
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. */
|
/* 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);
|
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:
|
public:
|
||||||
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, IPageAllocator &allocator) {
|
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. */
|
/* Ensure that addresses and sizes are page aligned. */
|
||||||
@@ -363,32 +578,62 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
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 {
|
class KInitialPageAllocator : public KInitialPageTable::IPageAllocator {
|
||||||
private:
|
|
||||||
uintptr_t next_address;
|
|
||||||
public:
|
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) {
|
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() {
|
ALWAYS_INLINE void InitializeFromState(uintptr_t state_val) {
|
||||||
const uintptr_t final_address = this->next_address;
|
if (kern::GetTargetFirmware() >= kern::TargetFirmware_10_0_0) {
|
||||||
this->next_address = Null<uintptr_t>;
|
this->state = *reinterpret_cast<State *>(state_val);
|
||||||
return final_address;
|
} else {
|
||||||
|
this->state.next_address = state_val;
|
||||||
|
this->state.free_bitmap = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE uintptr_t GetFinalState() {
|
ALWAYS_INLINE void GetFinalState(State *out) {
|
||||||
return this->GetFinalNextAddress();
|
*out = this->state;
|
||||||
|
this->state = {};
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
virtual KPhysicalAddress Allocate() override {
|
virtual KPhysicalAddress Allocate() override {
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(this->next_address != Null<uintptr_t>);
|
MESOSPHERE_INIT_ABORT_UNLESS(this->state.next_address != Null<uintptr_t>);
|
||||||
const uintptr_t allocated = this->next_address;
|
uintptr_t allocated = this->state.next_address;
|
||||||
this->next_address += PageSize;
|
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);
|
std::memset(reinterpret_cast<void *>(allocated), 0, PageSize);
|
||||||
return allocated;
|
return allocated;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
public:
|
public:
|
||||||
struct InvalidTag{};
|
struct InvalidTag{};
|
||||||
|
|
||||||
|
enum ExtensionTag : u64 {
|
||||||
|
ExtensionTag_IsValidBit = (1ul << 56),
|
||||||
|
ExtensionTag_IsValid = (ExtensionTag_IsValidBit | (1ul << 0)),
|
||||||
|
ExtensionTag_IsBlockMask = (ExtensionTag_IsValidBit | (1ul << 1)),
|
||||||
|
};
|
||||||
|
|
||||||
enum Permission : u64 {
|
enum Permission : u64 {
|
||||||
Permission_KernelRWX = ((0ul << 53) | (1ul << 54) | (0ul << 6)),
|
Permission_KernelRWX = ((0ul << 53) | (1ul << 54) | (0ul << 6)),
|
||||||
Permission_KernelRX = ((0ul << 53) | (1ul << 54) | (2ul << 6)),
|
Permission_KernelRX = ((0ul << 53) | (1ul << 54) | (2ul << 6)),
|
||||||
@@ -89,7 +95,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
/* Construct a new attribute. */
|
/* Construct a new attribute. */
|
||||||
constexpr ALWAYS_INLINE PageTableEntry(Permission perm, PageAttribute p_a, Shareable share)
|
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 IsReadOnly() const { return this->GetBits(7, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 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 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 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) SetContiguousAllowed(bool en) { this->SetBit(55, !en); return *this; }
|
||||||
constexpr ALWAYS_INLINE decltype(auto) SetUserExecuteNever(bool en) { this->SetBit(54, 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;
|
return this->attributes == attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE u64 GetRawAttributesUnsafeForSwap() const {
|
||||||
|
return this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
constexpr ALWAYS_INLINE u64 GetRawAttributes() const {
|
constexpr ALWAYS_INLINE u64 GetRawAttributes() const {
|
||||||
return this->attributes;
|
return this->attributes;
|
||||||
@@ -186,7 +197,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE L1PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
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)
|
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(InvalidTag) : PageTableEntry(InvalidTag{}) { /* ... */ }
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE L3PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
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 {
|
constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const {
|
||||||
return this->SelectBits(12, 36);
|
return this->SelectBits(12, 36);
|
||||||
|
|||||||
@@ -20,6 +20,24 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constexpr size_t PageSize = 4_KB;
|
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)
|
#if 1 || defined(AMS_BUILD_FOR_AUDITING)
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace ams::exosphere {
|
|||||||
AMS_DEFINE_TARGET_FIRMWARE_ENUM(810),
|
AMS_DEFINE_TARGET_FIRMWARE_ENUM(810),
|
||||||
AMS_DEFINE_TARGET_FIRMWARE_ENUM(900),
|
AMS_DEFINE_TARGET_FIRMWARE_ENUM(900),
|
||||||
AMS_DEFINE_TARGET_FIRMWARE_ENUM(910),
|
AMS_DEFINE_TARGET_FIRMWARE_ENUM(910),
|
||||||
|
AMS_DEFINE_TARGET_FIRMWARE_ENUM(1000),
|
||||||
};
|
};
|
||||||
#undef AMS_DEFINE_TARGET_FIRMWARE_ENUM
|
#undef AMS_DEFINE_TARGET_FIRMWARE_ENUM
|
||||||
|
|
||||||
|
|||||||
@@ -54,15 +54,15 @@ namespace ams::erpt::sf {
|
|||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MAKE_SERVICE_COMMAND_META(SubmitContext),
|
MAKE_SERVICE_COMMAND_META(SubmitContext),
|
||||||
MAKE_SERVICE_COMMAND_META(CreateReport),
|
MAKE_SERVICE_COMMAND_META(CreateReport),
|
||||||
MAKE_SERVICE_COMMAND_META(SetInitialLaunchSettingsCompletionTime, hos::Version_300),
|
MAKE_SERVICE_COMMAND_META(SetInitialLaunchSettingsCompletionTime, hos::Version_3_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(ClearInitialLaunchSettingsCompletionTime, hos::Version_300),
|
MAKE_SERVICE_COMMAND_META(ClearInitialLaunchSettingsCompletionTime, hos::Version_3_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(UpdatePowerOnTime, hos::Version_300),
|
MAKE_SERVICE_COMMAND_META(UpdatePowerOnTime, hos::Version_3_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(UpdateAwakeTime, hos::Version_300),
|
MAKE_SERVICE_COMMAND_META(UpdateAwakeTime, hos::Version_3_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(SubmitMultipleCategoryContext, hos::Version_500),
|
MAKE_SERVICE_COMMAND_META(SubmitMultipleCategoryContext, hos::Version_5_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(UpdateApplicationLaunchTime, hos::Version_600),
|
MAKE_SERVICE_COMMAND_META(UpdateApplicationLaunchTime, hos::Version_6_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(ClearApplicationLaunchTime, hos::Version_600),
|
MAKE_SERVICE_COMMAND_META(ClearApplicationLaunchTime, hos::Version_6_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(SubmitAttachment, hos::Version_800),
|
MAKE_SERVICE_COMMAND_META(SubmitAttachment, hos::Version_8_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(CreateReportWithAttachments, hos::Version_800),
|
MAKE_SERVICE_COMMAND_META(CreateReportWithAttachments, hos::Version_8_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ namespace ams::erpt::sf {
|
|||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MAKE_SERVICE_COMMAND_META(GetReportList),
|
MAKE_SERVICE_COMMAND_META(GetReportList),
|
||||||
MAKE_SERVICE_COMMAND_META(GetEvent),
|
MAKE_SERVICE_COMMAND_META(GetEvent),
|
||||||
MAKE_SERVICE_COMMAND_META(CleanupReports, hos::Version_400),
|
MAKE_SERVICE_COMMAND_META(CleanupReports, hos::Version_4_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(DeleteReport, hos::Version_500),
|
MAKE_SERVICE_COMMAND_META(DeleteReport, hos::Version_5_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetStorageUsageStatistics, hos::Version_500),
|
MAKE_SERVICE_COMMAND_META(GetStorageUsageStatistics, hos::Version_5_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetAttachmentList, hos::Version_800),
|
MAKE_SERVICE_COMMAND_META(GetAttachmentList, hos::Version_8_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace ams::erpt::sf {
|
|||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MAKE_SERVICE_COMMAND_META(OpenReport),
|
MAKE_SERVICE_COMMAND_META(OpenReport),
|
||||||
MAKE_SERVICE_COMMAND_META(OpenManager),
|
MAKE_SERVICE_COMMAND_META(OpenManager),
|
||||||
MAKE_SERVICE_COMMAND_META(OpenAttachment, hos::Version_800),
|
MAKE_SERVICE_COMMAND_META(OpenAttachment, hos::Version_8_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,17 @@
|
|||||||
|
|
||||||
namespace ams::fs {
|
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 MountCode(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id);
|
||||||
Result MountCodeForAtmosphere(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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ namespace ams::fssrv::impl {
|
|||||||
MAKE_SERVICE_COMMAND_META(GetSize),
|
MAKE_SERVICE_COMMAND_META(GetSize),
|
||||||
|
|
||||||
/* 4.0.0- */
|
/* 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),
|
MAKE_SERVICE_COMMAND_META(GetTotalSpaceSize),
|
||||||
|
|
||||||
/* 3.0.0- */
|
/* 3.0.0- */
|
||||||
MAKE_SERVICE_COMMAND_META(CleanDirectoryRecursively, hos::Version_300),
|
MAKE_SERVICE_COMMAND_META(CleanDirectoryRecursively, hos::Version_3_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetFileTimeStampRaw, hos::Version_300),
|
MAKE_SERVICE_COMMAND_META(GetFileTimeStampRaw, hos::Version_3_0_0),
|
||||||
|
|
||||||
/* 4.0.0- */
|
/* 4.0.0- */
|
||||||
MAKE_SERVICE_COMMAND_META(QueryEntry, hos::Version_400),
|
MAKE_SERVICE_COMMAND_META(QueryEntry, hos::Version_4_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace ams::fssrv::impl {
|
|||||||
MAKE_SERVICE_COMMAND_META(GetSize),
|
MAKE_SERVICE_COMMAND_META(GetSize),
|
||||||
|
|
||||||
/* 4.0.0- */
|
/* 4.0.0- */
|
||||||
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_400),
|
MAKE_SERVICE_COMMAND_META(OperateRange, hos::Version_4_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere/fssystem/fssystem_utility.hpp>
|
#include <stratosphere/fssystem/fssystem_utility.hpp>
|
||||||
#include <stratosphere/fssystem/fssystem_external_code.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.hpp>
|
||||||
#include <stratosphere/fssystem/fssystem_partition_file_system_meta.hpp>
|
#include <stratosphere/fssystem/fssystem_partition_file_system_meta.hpp>
|
||||||
#include <stratosphere/fssystem/fssystem_path_tool.hpp>
|
#include <stratosphere/fssystem/fssystem_path_tool.hpp>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,19 +20,20 @@
|
|||||||
namespace ams::hos {
|
namespace ams::hos {
|
||||||
|
|
||||||
enum Version : u16 {
|
enum Version : u16 {
|
||||||
Version_Min = 0,
|
Version_Min = 0,
|
||||||
Version_100 = Version_Min,
|
Version_1_0_0 = Version_Min,
|
||||||
Version_200 = 1,
|
Version_2_0_0 = 1,
|
||||||
Version_300 = 2,
|
Version_3_0_0 = 2,
|
||||||
Version_400 = 3,
|
Version_4_0_0 = 3,
|
||||||
Version_500 = 4,
|
Version_5_0_0 = 4,
|
||||||
Version_600 = 5,
|
Version_6_0_0 = 5,
|
||||||
Version_700 = 6,
|
Version_7_0_0 = 6,
|
||||||
Version_800 = 7,
|
Version_8_0_0 = 7,
|
||||||
Version_810 = 8,
|
Version_8_1_0 = 8,
|
||||||
Version_900 = 9,
|
Version_9_0_0 = 9,
|
||||||
Version_910 = 10,
|
Version_9_1_0 = 10,
|
||||||
Version_Current = Version_910,
|
Version_10_0_0 = 11,
|
||||||
|
Version_Current = Version_10_0_0,
|
||||||
Version_Max = 32,
|
Version_Max = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace ams::ldr::pm {
|
|||||||
Result GetProgramInfo(ProgramInfo *out, const ncm::ProgramLocation &loc);
|
Result GetProgramInfo(ProgramInfo *out, const ncm::ProgramLocation &loc);
|
||||||
Result PinProgram(PinId *out, const ncm::ProgramLocation &loc);
|
Result PinProgram(PinId *out, const ncm::ProgramLocation &loc);
|
||||||
Result UnpinProgram(PinId pin_id);
|
Result UnpinProgram(PinId pin_id);
|
||||||
|
Result SetEnabledProgramVerification(bool enabled);
|
||||||
Result HasLaunchedProgram(bool *out, ncm::ProgramId program_id);
|
Result HasLaunchedProgram(bool *out, ncm::ProgramId program_id);
|
||||||
|
|
||||||
/* Atmosphere extension API. */
|
/* Atmosphere extension API. */
|
||||||
|
|||||||
@@ -221,7 +221,8 @@ namespace ams::ldr {
|
|||||||
};
|
};
|
||||||
|
|
||||||
u32 magic;
|
u32 magic;
|
||||||
u8 reserved_04[8];
|
u32 signature_key_generation;
|
||||||
|
u8 reserved_08[4];
|
||||||
u8 flags;
|
u8 flags;
|
||||||
u8 reserved_0D;
|
u8 reserved_0D;
|
||||||
u8 main_thread_priority;
|
u8 main_thread_priority;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace ams::lr {
|
|||||||
|
|
||||||
Result RegisterAddOnContentStorage(ncm::DataId id, ncm::ApplicationId application_id, ncm::StorageId storage_id) {
|
Result RegisterAddOnContentStorage(ncm::DataId id, ncm::ApplicationId application_id, ncm::StorageId storage_id) {
|
||||||
AMS_ASSERT(this->interface);
|
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);
|
return this->interface->RegisterAddOnContentStorage(id, application_id, storage_id);
|
||||||
} else {
|
} else {
|
||||||
return this->interface->RegisterAddOnContentStorageDeprecated(id, storage_id);
|
return this->interface->RegisterAddOnContentStorageDeprecated(id, storage_id);
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ namespace ams::lr {
|
|||||||
virtual Result UnregisterApplicationAddOnContent(ncm::ApplicationId id) = 0;
|
virtual Result UnregisterApplicationAddOnContent(ncm::ApplicationId id) = 0;
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MAKE_SERVICE_COMMAND_META(ResolveAddOnContentPath, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(ResolveAddOnContentPath, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RegisterAddOnContentStorageDeprecated, hos::Version_200, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(RegisterAddOnContentStorageDeprecated, hos::Version_2_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RegisterAddOnContentStorage, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RegisterAddOnContentStorage, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(UnregisterAllAddOnContentPath, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(UnregisterAllAddOnContentPath, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RefreshApplicationAddOnContent, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RefreshApplicationAddOnContent, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(UnregisterApplicationAddOnContent, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(UnregisterApplicationAddOnContent, hos::Version_9_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -88,27 +88,27 @@ namespace ams::lr {
|
|||||||
MAKE_SERVICE_COMMAND_META(ResolveApplicationControlPath),
|
MAKE_SERVICE_COMMAND_META(ResolveApplicationControlPath),
|
||||||
MAKE_SERVICE_COMMAND_META(ResolveApplicationHtmlDocumentPath),
|
MAKE_SERVICE_COMMAND_META(ResolveApplicationHtmlDocumentPath),
|
||||||
MAKE_SERVICE_COMMAND_META(ResolveDataPath),
|
MAKE_SERVICE_COMMAND_META(ResolveDataPath),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectApplicationControlPathDeprecated, hos::Version_100, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(RedirectApplicationControlPathDeprecated, hos::Version_1_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectApplicationControlPath, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RedirectApplicationControlPath, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectApplicationHtmlDocumentPathDeprecated, hos::Version_100, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(RedirectApplicationHtmlDocumentPathDeprecated, hos::Version_1_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectApplicationHtmlDocumentPath, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RedirectApplicationHtmlDocumentPath, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(ResolveApplicationLegalInformationPath),
|
MAKE_SERVICE_COMMAND_META(ResolveApplicationLegalInformationPath),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectApplicationLegalInformationPathDeprecated, hos::Version_100, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(RedirectApplicationLegalInformationPathDeprecated, hos::Version_1_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectApplicationLegalInformationPath, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RedirectApplicationLegalInformationPath, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(Refresh),
|
MAKE_SERVICE_COMMAND_META(Refresh),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathDeprecated, hos::Version_500, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathDeprecated, hos::Version_5_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPath, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPath, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(ClearApplicationRedirectionDeprecated, hos::Version_500, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(ClearApplicationRedirectionDeprecated, hos::Version_5_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(ClearApplicationRedirection, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(ClearApplicationRedirection, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(EraseProgramRedirection, hos::Version_500),
|
MAKE_SERVICE_COMMAND_META(EraseProgramRedirection, hos::Version_5_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(EraseApplicationControlRedirection, hos::Version_500),
|
MAKE_SERVICE_COMMAND_META(EraseApplicationControlRedirection, hos::Version_5_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(EraseApplicationHtmlDocumentRedirection, hos::Version_500),
|
MAKE_SERVICE_COMMAND_META(EraseApplicationHtmlDocumentRedirection, hos::Version_5_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(EraseApplicationLegalInformationRedirection, hos::Version_500),
|
MAKE_SERVICE_COMMAND_META(EraseApplicationLegalInformationRedirection, hos::Version_5_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(ResolveProgramPathForDebug, hos::Version_700),
|
MAKE_SERVICE_COMMAND_META(ResolveProgramPathForDebug, hos::Version_7_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectProgramPathForDebug, hos::Version_700),
|
MAKE_SERVICE_COMMAND_META(RedirectProgramPathForDebug, hos::Version_7_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathForDebugDeprecated, hos::Version_700, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathForDebugDeprecated, hos::Version_7_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathForDebug, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RedirectApplicationProgramPathForDebug, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(EraseProgramRedirectionForDebug, hos::Version_700),
|
MAKE_SERVICE_COMMAND_META(EraseProgramRedirectionForDebug, hos::Version_7_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -56,19 +56,19 @@ namespace ams::lr {
|
|||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MAKE_SERVICE_COMMAND_META(ResolveProgramPath),
|
MAKE_SERVICE_COMMAND_META(ResolveProgramPath),
|
||||||
MAKE_SERVICE_COMMAND_META(RegisterProgramPathDeprecated, hos::Version_100, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(RegisterProgramPathDeprecated, hos::Version_1_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RegisterProgramPath, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RegisterProgramPath, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(UnregisterProgramPath),
|
MAKE_SERVICE_COMMAND_META(UnregisterProgramPath),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectProgramPathDeprecated, hos::Version_100, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(RedirectProgramPathDeprecated, hos::Version_1_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectProgramPath, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RedirectProgramPath, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(ResolveHtmlDocumentPath, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(ResolveHtmlDocumentPath, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RegisterHtmlDocumentPathDeprecated, hos::Version_200, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(RegisterHtmlDocumentPathDeprecated, hos::Version_2_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RegisterHtmlDocumentPath, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RegisterHtmlDocumentPath, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(UnregisterHtmlDocumentPath, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(UnregisterHtmlDocumentPath, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectHtmlDocumentPathDeprecated, hos::Version_200, hos::Version_810),
|
MAKE_SERVICE_COMMAND_META(RedirectHtmlDocumentPathDeprecated, hos::Version_2_0_0, hos::Version_8_1_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RedirectHtmlDocumentPath, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RedirectHtmlDocumentPath, hos::Version_9_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(Refresh, hos::Version_700),
|
MAKE_SERVICE_COMMAND_META(Refresh, hos::Version_7_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RefreshExcluding, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(RefreshExcluding, hos::Version_9_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace ams::lr {
|
|||||||
|
|
||||||
void RedirectApplicationControlPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
void RedirectApplicationControlPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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));
|
R_ABORT_UNLESS(this->interface->RedirectApplicationControlPath(path, id, owner_id));
|
||||||
} else {
|
} else {
|
||||||
R_ABORT_UNLESS(this->interface->RedirectApplicationControlPathDeprecated(path, id));
|
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) {
|
void RedirectApplicationHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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));
|
R_ABORT_UNLESS(this->interface->RedirectApplicationHtmlDocumentPath(path, id, owner_id));
|
||||||
} else {
|
} else {
|
||||||
R_ABORT_UNLESS(this->interface->RedirectApplicationHtmlDocumentPathDeprecated(path, id));
|
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) {
|
void RedirectApplicationLegalInformationPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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));
|
R_ABORT_UNLESS(this->interface->RedirectApplicationLegalInformationPath(path, id, owner_id));
|
||||||
} else {
|
} else {
|
||||||
R_ABORT_UNLESS(this->interface->RedirectApplicationLegalInformationPathDeprecated(path, id));
|
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) {
|
void RedirectApplicationProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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));
|
R_ABORT_UNLESS(this->interface->RedirectApplicationProgramPath(path, id, owner_id));
|
||||||
} else {
|
} else {
|
||||||
R_ABORT_UNLESS(this->interface->RedirectApplicationProgramPathDeprecated(path, id));
|
R_ABORT_UNLESS(this->interface->RedirectApplicationProgramPathDeprecated(path, id));
|
||||||
@@ -114,13 +114,13 @@ namespace ams::lr {
|
|||||||
|
|
||||||
Result ClearApplicationRedirection() {
|
Result ClearApplicationRedirection() {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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);
|
return this->ClearApplicationRedirection(nullptr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ClearApplicationRedirection(const ncm::ProgramId *excluding_ids, size_t num_ids) {
|
Result ClearApplicationRedirection(const ncm::ProgramId *excluding_ids, size_t num_ids) {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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));
|
return this->interface->ClearApplicationRedirection(sf::InArray<ncm::ProgramId>(excluding_ids, num_ids));
|
||||||
} else {
|
} else {
|
||||||
return this->interface->ClearApplicationRedirectionDeprecated();
|
return this->interface->ClearApplicationRedirectionDeprecated();
|
||||||
@@ -159,7 +159,7 @@ namespace ams::lr {
|
|||||||
|
|
||||||
void RedirectApplicationProgramPathForDebug(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
void RedirectApplicationProgramPathForDebug(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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));
|
R_ABORT_UNLESS(this->interface->RedirectApplicationProgramPathForDebug(path, id, owner_id));
|
||||||
} else {
|
} else {
|
||||||
R_ABORT_UNLESS(this->interface->RedirectApplicationProgramPathForDebugDeprecated(path, id));
|
R_ABORT_UNLESS(this->interface->RedirectApplicationProgramPathForDebugDeprecated(path, id));
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace ams::lr {
|
|||||||
MAKE_SERVICE_COMMAND_META(OpenLocationResolver),
|
MAKE_SERVICE_COMMAND_META(OpenLocationResolver),
|
||||||
MAKE_SERVICE_COMMAND_META(OpenRegisteredLocationResolver),
|
MAKE_SERVICE_COMMAND_META(OpenRegisteredLocationResolver),
|
||||||
MAKE_SERVICE_COMMAND_META(RefreshLocationResolver),
|
MAKE_SERVICE_COMMAND_META(RefreshLocationResolver),
|
||||||
MAKE_SERVICE_COMMAND_META(OpenAddOnContentLocationResolver, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(OpenAddOnContentLocationResolver, hos::Version_2_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace ams::lr {
|
|||||||
|
|
||||||
Result RegisterProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
Result RegisterProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
||||||
AMS_ASSERT(this->interface);
|
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);
|
return this->interface->RegisterProgramPath(path, id, owner_id);
|
||||||
} else {
|
} else {
|
||||||
return this->interface->RegisterProgramPathDeprecated(path, id);
|
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) {
|
void RedirectProgramPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
||||||
AMS_ASSERT(this->interface);
|
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));
|
R_ABORT_UNLESS(this->interface->RedirectProgramPath(path, id, owner_id));
|
||||||
} else {
|
} else {
|
||||||
R_ABORT_UNLESS(this->interface->RedirectProgramPathDeprecated(path, id));
|
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) {
|
Result RegisterHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
||||||
AMS_ASSERT(this->interface);
|
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);
|
return this->interface->RegisterHtmlDocumentPath(path, id, owner_id);
|
||||||
} else {
|
} else {
|
||||||
return this->interface->RegisterHtmlDocumentPathDeprecated(path, id);
|
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) {
|
void RedirectHtmlDocumentPath(const Path &path, ncm::ProgramId id, ncm::ProgramId owner_id) {
|
||||||
AMS_ASSERT(this->interface);
|
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));
|
R_ABORT_UNLESS(this->interface->RedirectHtmlDocumentPath(path, id, owner_id));
|
||||||
} else {
|
} else {
|
||||||
R_ABORT_UNLESS(this->interface->RedirectHtmlDocumentPathDeprecated(path, id));
|
R_ABORT_UNLESS(this->interface->RedirectHtmlDocumentPathDeprecated(path, id));
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include <stratosphere/ncm/ncm_install_task_base.hpp>
|
#include <stratosphere/ncm/ncm_install_task_base.hpp>
|
||||||
#include <stratosphere/ncm/ncm_install_task_data.hpp>
|
#include <stratosphere/ncm/ncm_install_task_data.hpp>
|
||||||
#include <stratosphere/ncm/ncm_install_task_occupied_size.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_base.hpp>
|
||||||
#include <stratosphere/ncm/ncm_package_install_task.hpp>
|
#include <stratosphere/ncm/ncm_package_install_task.hpp>
|
||||||
#include <stratosphere/ncm/ncm_package_system_update_task.hpp>
|
#include <stratosphere/ncm/ncm_package_system_update_task.hpp>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldBuildDatabase() const {
|
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 {
|
bool ShouldImportDatabaseFromSignedSystemPartitionOnSd() const {
|
||||||
|
|||||||
@@ -30,14 +30,32 @@
|
|||||||
|
|
||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
|
|
||||||
class ContentMetaMemoryResource {
|
class ContentMetaMemoryResource : public MemoryResource {
|
||||||
private:
|
private:
|
||||||
mem::StandardAllocator allocator;
|
mem::StandardAllocator allocator;
|
||||||
sf::StandardAllocatorMemoryResource memory_resource;
|
size_t peak_total_alloc_size;
|
||||||
|
size_t peak_alloc_size;
|
||||||
public:
|
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 {
|
struct SystemSaveDataInfo {
|
||||||
@@ -127,6 +145,7 @@ namespace ams::ncm {
|
|||||||
virtual Result ActivateContentMetaDatabase(StorageId storage_id) override;
|
virtual Result ActivateContentMetaDatabase(StorageId storage_id) override;
|
||||||
virtual Result InactivateContentMetaDatabase(StorageId storage_id) override;
|
virtual Result InactivateContentMetaDatabase(StorageId storage_id) override;
|
||||||
virtual Result InvalidateRightsIdCache() override;
|
virtual Result InvalidateRightsIdCache() override;
|
||||||
|
virtual Result GetMemoryReport(sf::Out<MemoryReport> out) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,25 +144,25 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
Result GetRightsId(ams::fs::RightsId *out_rights_id, PlaceHolderId placeholder_id) {
|
Result GetRightsId(ams::fs::RightsId *out_rights_id, PlaceHolderId placeholder_id) {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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);
|
return this->interface->GetRightsIdFromPlaceHolderIdDeprecated(out_rights_id, placeholder_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetRightsId(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id) {
|
Result GetRightsId(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id) {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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);
|
return this->interface->GetRightsIdFromPlaceHolderId(out_rights_id, placeholder_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetRightsId(ams::fs::RightsId *out_rights_id, ContentId content_id) {
|
Result GetRightsId(ams::fs::RightsId *out_rights_id, ContentId content_id) {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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);
|
return this->interface->GetRightsIdFromContentIdDeprecated(out_rights_id, content_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetRightsId(ncm::RightsId *out_rights_id, ContentId content_id) {
|
Result GetRightsId(ncm::RightsId *out_rights_id, ContentId content_id) {
|
||||||
AMS_ASSERT(this->interface != nullptr);
|
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);
|
return this->interface->GetRightsIdFromContentId(out_rights_id, content_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere/ncm/ncm_i_content_storage.hpp>
|
#include <stratosphere/ncm/ncm_i_content_storage.hpp>
|
||||||
#include <stratosphere/ncm/ncm_i_content_meta_database.hpp>
|
#include <stratosphere/ncm/ncm_i_content_meta_database.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_memory_report.hpp>
|
||||||
|
|
||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ namespace ams::ncm {
|
|||||||
ActivateContentMetaDatabase = 11,
|
ActivateContentMetaDatabase = 11,
|
||||||
InactivateContentMetaDatabase = 12,
|
InactivateContentMetaDatabase = 12,
|
||||||
InvalidateRightsIdCache = 13,
|
InvalidateRightsIdCache = 13,
|
||||||
|
GetMemoryReport = 14,
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
virtual Result CreateContentStorage(StorageId storage_id) = 0;
|
virtual Result CreateContentStorage(StorageId storage_id) = 0;
|
||||||
@@ -52,6 +54,7 @@ namespace ams::ncm {
|
|||||||
virtual Result ActivateContentMetaDatabase(StorageId storage_id) = 0;
|
virtual Result ActivateContentMetaDatabase(StorageId storage_id) = 0;
|
||||||
virtual Result InactivateContentMetaDatabase(StorageId storage_id) = 0;
|
virtual Result InactivateContentMetaDatabase(StorageId storage_id) = 0;
|
||||||
virtual Result InvalidateRightsIdCache() = 0;
|
virtual Result InvalidateRightsIdCache() = 0;
|
||||||
|
virtual Result GetMemoryReport(sf::Out<MemoryReport> out) = 0;
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MAKE_SERVICE_COMMAND_META(CreateContentStorage),
|
MAKE_SERVICE_COMMAND_META(CreateContentStorage),
|
||||||
@@ -60,14 +63,15 @@ namespace ams::ncm {
|
|||||||
MAKE_SERVICE_COMMAND_META(VerifyContentMetaDatabase),
|
MAKE_SERVICE_COMMAND_META(VerifyContentMetaDatabase),
|
||||||
MAKE_SERVICE_COMMAND_META(OpenContentStorage),
|
MAKE_SERVICE_COMMAND_META(OpenContentStorage),
|
||||||
MAKE_SERVICE_COMMAND_META(OpenContentMetaDatabase),
|
MAKE_SERVICE_COMMAND_META(OpenContentMetaDatabase),
|
||||||
MAKE_SERVICE_COMMAND_META(CloseContentStorageForcibly, 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_100, hos::Version_100),
|
MAKE_SERVICE_COMMAND_META(CloseContentMetaDatabaseForcibly, hos::Version_1_0_0, hos::Version_1_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(CleanupContentMetaDatabase),
|
MAKE_SERVICE_COMMAND_META(CleanupContentMetaDatabase),
|
||||||
MAKE_SERVICE_COMMAND_META(ActivateContentStorage, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(ActivateContentStorage, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(InactivateContentStorage, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(InactivateContentStorage, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(ActivateContentMetaDatabase, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(ActivateContentMetaDatabase, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(InactivateContentMetaDatabase, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(InactivateContentMetaDatabase, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(InvalidateRightsIdCache, hos::Version_900),
|
MAKE_SERVICE_COMMAND_META(InvalidateRightsIdCache, hos::Version_9_0_0),
|
||||||
|
MAKE_SERVICE_COMMAND_META(GetMemoryReport, hos::Version_10_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ namespace ams::ncm {
|
|||||||
GetAttributes = 18,
|
GetAttributes = 18,
|
||||||
GetRequiredApplicationVersion = 19,
|
GetRequiredApplicationVersion = 19,
|
||||||
GetContentIdByTypeAndIdOffset = 20,
|
GetContentIdByTypeAndIdOffset = 20,
|
||||||
|
GetCount = 21,
|
||||||
|
GetOwnerApplicationId = 22,
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
/* Actual commands. */
|
/* Actual commands. */
|
||||||
@@ -67,6 +69,8 @@ namespace ams::ncm {
|
|||||||
virtual Result GetAttributes(sf::Out<u8> out_attributes, const ContentMetaKey &key) = 0;
|
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 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 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:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MAKE_SERVICE_COMMAND_META(Set),
|
MAKE_SERVICE_COMMAND_META(Set),
|
||||||
@@ -88,8 +92,10 @@ namespace ams::ncm {
|
|||||||
MAKE_SERVICE_COMMAND_META(HasContent),
|
MAKE_SERVICE_COMMAND_META(HasContent),
|
||||||
MAKE_SERVICE_COMMAND_META(ListContentMetaInfo),
|
MAKE_SERVICE_COMMAND_META(ListContentMetaInfo),
|
||||||
MAKE_SERVICE_COMMAND_META(GetAttributes),
|
MAKE_SERVICE_COMMAND_META(GetAttributes),
|
||||||
MAKE_SERVICE_COMMAND_META(GetRequiredApplicationVersion, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(GetRequiredApplicationVersion, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetContentIdByTypeAndIdOffset, hos::Version_500),
|
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),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -110,20 +110,20 @@ namespace ams::ncm {
|
|||||||
MAKE_SERVICE_COMMAND_META(ListContentId),
|
MAKE_SERVICE_COMMAND_META(ListContentId),
|
||||||
MAKE_SERVICE_COMMAND_META(GetSizeFromContentId),
|
MAKE_SERVICE_COMMAND_META(GetSizeFromContentId),
|
||||||
MAKE_SERVICE_COMMAND_META(DisableForcibly),
|
MAKE_SERVICE_COMMAND_META(DisableForcibly),
|
||||||
MAKE_SERVICE_COMMAND_META(RevertToPlaceHolder, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(RevertToPlaceHolder, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(SetPlaceHolderSize, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(SetPlaceHolderSize, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(ReadContentIdFile, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(ReadContentIdFile, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderIdDeprecated, hos::Version_200, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderIdDeprecated, hos::Version_2_0_0, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderId, hos::Version_300),
|
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderId, hos::Version_3_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetRightsIdFromContentIdDeprecated, hos::Version_200, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(GetRightsIdFromContentIdDeprecated, hos::Version_2_0_0, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetRightsIdFromContentId, hos::Version_300),
|
MAKE_SERVICE_COMMAND_META(GetRightsIdFromContentId, hos::Version_3_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(WriteContentForDebug, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(WriteContentForDebug, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetFreeSpaceSize, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(GetFreeSpaceSize, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetTotalSpaceSize, hos::Version_200),
|
MAKE_SERVICE_COMMAND_META(GetTotalSpaceSize, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(FlushPlaceHolder, hos::Version_300),
|
MAKE_SERVICE_COMMAND_META(FlushPlaceHolder, hos::Version_3_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetSizeFromPlaceHolderId, hos::Version_400),
|
MAKE_SERVICE_COMMAND_META(GetSizeFromPlaceHolderId, hos::Version_4_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(RepairInvalidFileAttribute, hos::Version_400),
|
MAKE_SERVICE_COMMAND_META(RepairInvalidFileAttribute, hos::Version_4_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderIdWithCache, hos::Version_800),
|
MAKE_SERVICE_COMMAND_META(GetRightsIdFromPlaceHolderIdWithCache, hos::Version_8_0_0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -95,6 +95,7 @@ namespace ams::ncm {
|
|||||||
static const SystemProgramId Dt;
|
static const SystemProgramId Dt;
|
||||||
static const SystemProgramId Nd;
|
static const SystemProgramId Nd;
|
||||||
static const SystemProgramId Ngct;
|
static const SystemProgramId Ngct;
|
||||||
|
static const SystemProgramId Pgl;
|
||||||
|
|
||||||
static const SystemProgramId End;
|
static const SystemProgramId End;
|
||||||
};
|
};
|
||||||
@@ -192,6 +193,7 @@ namespace ams::ncm {
|
|||||||
inline constexpr const SystemProgramId SystemProgramId::Dt = { 0x010000000000003Ful };
|
inline constexpr const SystemProgramId SystemProgramId::Dt = { 0x010000000000003Ful };
|
||||||
inline constexpr const SystemProgramId SystemProgramId::Nd = { 0x0100000000000040ul };
|
inline constexpr const SystemProgramId SystemProgramId::Nd = { 0x0100000000000040ul };
|
||||||
inline constexpr const SystemProgramId SystemProgramId::Ngct = { 0x0100000000000041ul };
|
inline constexpr const SystemProgramId SystemProgramId::Ngct = { 0x0100000000000041ul };
|
||||||
|
inline constexpr const SystemProgramId SystemProgramId::Pgl = { 0x0100000000000042ul };
|
||||||
|
|
||||||
inline constexpr const SystemProgramId SystemProgramId::End = { 0x01000000000007FFul };
|
inline constexpr const SystemProgramId SystemProgramId::End = { 0x01000000000007FFul };
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace ams::psc::sf {
|
|||||||
MAKE_SERVICE_COMMAND_META(GetRequest),
|
MAKE_SERVICE_COMMAND_META(GetRequest),
|
||||||
MAKE_SERVICE_COMMAND_META(Acknowledge),
|
MAKE_SERVICE_COMMAND_META(Acknowledge),
|
||||||
MAKE_SERVICE_COMMAND_META(Finalize),
|
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... */
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace ams::spl {
|
|||||||
|
|
||||||
HardwareType GetHardwareType();
|
HardwareType GetHardwareType();
|
||||||
MemoryArrangement GetMemoryArrangement();
|
MemoryArrangement GetMemoryArrangement();
|
||||||
|
bool IsDisabledProgramVerification();
|
||||||
bool IsDevelopmentHardware();
|
bool IsDevelopmentHardware();
|
||||||
bool IsDevelopmentFunctionEnabled();
|
bool IsDevelopmentFunctionEnabled();
|
||||||
bool IsMariko();
|
bool IsMariko();
|
||||||
|
|||||||
@@ -318,8 +318,12 @@ namespace ams::svc::aarch64::lp64 {
|
|||||||
return ::svcQueryPhysicalAddress(reinterpret_cast<::PhysicalMemoryInfo *>(out_info), address);
|
return ::svcQueryPhysicalAddress(reinterpret_cast<::PhysicalMemoryInfo *>(out_info), address);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Result QueryIoMapping(::ams::svc::Address *out_address, ::ams::svc::PhysicalAddress physical_address, ::ams::svc::Size size) {
|
ALWAYS_INLINE Result QueryIoMapping(::ams::svc::Address *out_address, ::ams::svc::Size *out_size, ::ams::svc::PhysicalAddress physical_address, ::ams::svc::Size size) {
|
||||||
return ::svcQueryIoMapping(reinterpret_cast<u64 *>(out_address), physical_address, size);
|
return ::svcQueryIoMapping(reinterpret_cast<u64 *>(out_address), reinterpret_cast<u64 *>(out_size), physical_address, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE Result LegacyQueryIoMapping(::ams::svc::Address *out_address, ::ams::svc::PhysicalAddress physical_address, ::ams::svc::Size size) {
|
||||||
|
return ::svcLegacyQueryIoMapping(reinterpret_cast<u64 *>(out_address), physical_address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Result CreateDeviceAddressSpace(::ams::svc::Handle *out_handle, uint64_t das_address, uint64_t das_size) {
|
ALWAYS_INLINE Result CreateDeviceAddressSpace(::ams::svc::Handle *out_handle, uint64_t das_address, uint64_t das_size) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ namespace ams::boot2 {
|
|||||||
ncm::SystemProgramId::NvServices, /* nvservices */
|
ncm::SystemProgramId::NvServices, /* nvservices */
|
||||||
ncm::SystemProgramId::NvnFlinger, /* nvnflinger */
|
ncm::SystemProgramId::NvnFlinger, /* nvnflinger */
|
||||||
ncm::SystemProgramId::Vi, /* vi */
|
ncm::SystemProgramId::Vi, /* vi */
|
||||||
|
ncm::SystemProgramId::Pgl, /* pgl */
|
||||||
ncm::SystemProgramId::Ns, /* ns */
|
ncm::SystemProgramId::Ns, /* ns */
|
||||||
ncm::SystemProgramId::LogManager, /* lm */
|
ncm::SystemProgramId::LogManager, /* lm */
|
||||||
ncm::SystemProgramId::Ppc, /* ppc */
|
ncm::SystemProgramId::Ppc, /* ppc */
|
||||||
@@ -84,6 +85,7 @@ namespace ams::boot2 {
|
|||||||
ncm::SystemProgramId::NvServices, /* nvservices */
|
ncm::SystemProgramId::NvServices, /* nvservices */
|
||||||
ncm::SystemProgramId::NvnFlinger, /* nvnflinger */
|
ncm::SystemProgramId::NvnFlinger, /* nvnflinger */
|
||||||
ncm::SystemProgramId::Vi, /* vi */
|
ncm::SystemProgramId::Vi, /* vi */
|
||||||
|
ncm::SystemProgramId::Pgl, /* pgl */
|
||||||
ncm::SystemProgramId::Ns, /* ns */
|
ncm::SystemProgramId::Ns, /* ns */
|
||||||
ncm::SystemProgramId::LogManager, /* lm */
|
ncm::SystemProgramId::LogManager, /* lm */
|
||||||
ncm::SystemProgramId::Ppc, /* ppc */
|
ncm::SystemProgramId::Ppc, /* ppc */
|
||||||
@@ -133,19 +135,29 @@ namespace ams::boot2 {
|
|||||||
return c == '\r' || c == '\n';
|
return c == '\r' || c == '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool IsAllowedLaunchProgram(const ncm::ProgramLocation &loc) {
|
||||||
|
if (loc.program_id == ncm::SystemProgramId::Pgl) {
|
||||||
|
return hos::GetVersion() >= hos::Version_10_0_0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void LaunchProgram(os::ProcessId *out_process_id, const ncm::ProgramLocation &loc, u32 launch_flags) {
|
void LaunchProgram(os::ProcessId *out_process_id, const ncm::ProgramLocation &loc, u32 launch_flags) {
|
||||||
os::ProcessId process_id = os::InvalidProcessId;
|
os::ProcessId process_id = os::InvalidProcessId;
|
||||||
|
|
||||||
/* Launch, lightly validate result. */
|
/* Only launch the process if we're allowed to. */
|
||||||
{
|
if (IsAllowedLaunchProgram(loc)) {
|
||||||
const auto launch_result = pm::shell::LaunchProgram(&process_id, loc, launch_flags);
|
/* Launch, lightly validate result. */
|
||||||
AMS_ABORT_UNLESS(!(svc::ResultOutOfResource::Includes(launch_result)));
|
{
|
||||||
AMS_ABORT_UNLESS(!(svc::ResultOutOfMemory::Includes(launch_result)));
|
const auto launch_result = pm::shell::LaunchProgram(&process_id, loc, launch_flags);
|
||||||
AMS_ABORT_UNLESS(!(svc::ResultLimitReached::Includes(launch_result)));
|
AMS_ABORT_UNLESS(!(svc::ResultOutOfResource::Includes(launch_result)));
|
||||||
}
|
AMS_ABORT_UNLESS(!(svc::ResultOutOfMemory::Includes(launch_result)));
|
||||||
|
AMS_ABORT_UNLESS(!(svc::ResultLimitReached::Includes(launch_result)));
|
||||||
|
}
|
||||||
|
|
||||||
if (out_process_id) {
|
if (out_process_id) {
|
||||||
*out_process_id = process_id;
|
*out_process_id = process_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,7 +320,7 @@ namespace ams::boot2 {
|
|||||||
|
|
||||||
/* Wait for other atmosphere mitm modules to initialize. */
|
/* Wait for other atmosphere mitm modules to initialize. */
|
||||||
R_ABORT_UNLESS(sm::mitm::WaitMitm(sm::ServiceName::Encode("set:sys")));
|
R_ABORT_UNLESS(sm::mitm::WaitMitm(sm::ServiceName::Encode("set:sys")));
|
||||||
if (hos::GetVersion() >= hos::Version_200) {
|
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||||
R_ABORT_UNLESS(sm::mitm::WaitMitm(sm::ServiceName::Encode("bpc")));
|
R_ABORT_UNLESS(sm::mitm::WaitMitm(sm::ServiceName::Encode("bpc")));
|
||||||
} else {
|
} else {
|
||||||
R_ABORT_UNLESS(sm::mitm::WaitMitm(sm::ServiceName::Encode("bpc:c")));
|
R_ABORT_UNLESS(sm::mitm::WaitMitm(sm::ServiceName::Encode("bpc:c")));
|
||||||
@@ -337,7 +349,7 @@ namespace ams::boot2 {
|
|||||||
if (maintenance) {
|
if (maintenance) {
|
||||||
LaunchList(AdditionalMaintenanceLaunchPrograms, NumAdditionalMaintenanceLaunchPrograms);
|
LaunchList(AdditionalMaintenanceLaunchPrograms, NumAdditionalMaintenanceLaunchPrograms);
|
||||||
/* Starting in 7.0.0, npns is launched during maintenance boot. */
|
/* Starting in 7.0.0, npns is launched during maintenance boot. */
|
||||||
if (hos::GetVersion() >= hos::Version_700) {
|
if (hos::GetVersion() >= hos::Version_7_0_0) {
|
||||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Npns, ncm::StorageId::BuiltInSystem), 0);
|
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Npns, ncm::StorageId::BuiltInSystem), 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ namespace ams::cfg {
|
|||||||
/* SD card helpers. */
|
/* SD card helpers. */
|
||||||
void GetPrivilegedProcessIdRange(os::ProcessId *out_min, os::ProcessId *out_max) {
|
void GetPrivilegedProcessIdRange(os::ProcessId *out_min, os::ProcessId *out_max) {
|
||||||
os::ProcessId min = os::InvalidProcessId, max = os::InvalidProcessId;
|
os::ProcessId min = os::InvalidProcessId, max = os::InvalidProcessId;
|
||||||
if (hos::GetVersion() >= hos::Version_500) {
|
if (hos::GetVersion() >= hos::Version_5_0_0) {
|
||||||
/* On 5.0.0+, we can get precise limits from svcGetSystemInfo. */
|
/* On 5.0.0+, we can get precise limits from svcGetSystemInfo. */
|
||||||
R_ABORT_UNLESS(svcGetSystemInfo(reinterpret_cast<u64 *>(&min), SystemInfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Minimum));
|
R_ABORT_UNLESS(svcGetSystemInfo(reinterpret_cast<u64 *>(&min), SystemInfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Minimum));
|
||||||
R_ABORT_UNLESS(svcGetSystemInfo(reinterpret_cast<u64 *>(&max), SystemInfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Maximum));
|
R_ABORT_UNLESS(svcGetSystemInfo(reinterpret_cast<u64 *>(&max), SystemInfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Maximum));
|
||||||
} else if (hos::GetVersion() >= hos::Version_400) {
|
} else if (hos::GetVersion() >= hos::Version_4_0_0) {
|
||||||
/* On 4.0.0-4.1.0, we can get the precise limits from normal svcGetInfo. */
|
/* On 4.0.0-4.1.0, we can get the precise limits from normal svcGetInfo. */
|
||||||
R_ABORT_UNLESS(svcGetInfo(reinterpret_cast<u64 *>(&min), InfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Minimum));
|
R_ABORT_UNLESS(svcGetInfo(reinterpret_cast<u64 *>(&min), InfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Minimum));
|
||||||
R_ABORT_UNLESS(svcGetInfo(reinterpret_cast<u64 *>(&max), InfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Maximum));
|
R_ABORT_UNLESS(svcGetInfo(reinterpret_cast<u64 *>(&max), InfoType_InitialProcessIdRange, INVALID_HANDLE, InitialProcessIdRangeInfo_Maximum));
|
||||||
|
|||||||
@@ -22,10 +22,19 @@ namespace ams::dd {
|
|||||||
const u64 aligned_addr = util::AlignDown(phys_addr, os::MemoryPageSize);
|
const u64 aligned_addr = util::AlignDown(phys_addr, os::MemoryPageSize);
|
||||||
const size_t offset = phys_addr - aligned_addr;
|
const size_t offset = phys_addr - aligned_addr;
|
||||||
const u64 aligned_size = size + offset;
|
const u64 aligned_size = size + offset;
|
||||||
R_TRY_CATCH(svcQueryIoMapping(&virtual_addr, aligned_addr, aligned_size)) {
|
if (hos::GetVersion() >= hos::Version_10_0_0) {
|
||||||
/* Official software handles this by returning 0. */
|
u64 region_size;
|
||||||
R_CATCH(svc::ResultNotFound) { return 0; }
|
R_TRY_CATCH(svcQueryIoMapping(&virtual_addr, ®ion_size, aligned_addr, aligned_size)) {
|
||||||
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
/* Official software handles this by returning 0. */
|
||||||
|
R_CATCH(svc::ResultNotFound) { return 0; }
|
||||||
|
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||||
|
AMS_ASSERT(region_size >= aligned_size);
|
||||||
|
} else {
|
||||||
|
R_TRY_CATCH(svcLegacyQueryIoMapping(&virtual_addr, aligned_addr, aligned_size)) {
|
||||||
|
/* Official software handles this by returning 0. */
|
||||||
|
R_CATCH(svc::ResultNotFound) { return 0; }
|
||||||
|
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||||
|
}
|
||||||
|
|
||||||
return static_cast<uintptr_t>(virtual_addr + offset);
|
return static_cast<uintptr_t>(virtual_addr + offset);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace ams::erpt::srv {
|
|||||||
R_TRY(fs::GetSaveDataAvailableSize(std::addressof(cur_savedata_size), SystemSaveDataId));
|
R_TRY(fs::GetSaveDataAvailableSize(std::addressof(cur_savedata_size), SystemSaveDataId));
|
||||||
|
|
||||||
if (cur_journal_size < SystemSaveDataJournalSize || cur_savedata_size < SystemSaveDataSize) {
|
if (cur_journal_size < SystemSaveDataJournalSize || cur_savedata_size < SystemSaveDataSize) {
|
||||||
if (hos::GetVersion() >= hos::Version_300) {
|
if (hos::GetVersion() >= hos::Version_3_0_0) {
|
||||||
R_TRY(fs::ExtendSaveData(fs::SaveDataSpaceId::System, SystemSaveDataId, SystemSaveDataSize, SystemSaveDataJournalSize));
|
R_TRY(fs::ExtendSaveData(fs::SaveDataSpaceId::System, SystemSaveDataId, SystemSaveDataSize, SystemSaveDataJournalSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace ams::erpt::srv {
|
|||||||
|
|
||||||
Result Reporter::CollectUniqueReportFields() {
|
Result Reporter::CollectUniqueReportFields() {
|
||||||
this->occurrence_tick = os::GetSystemTick();
|
this->occurrence_tick = os::GetSystemTick();
|
||||||
if (hos::GetVersion() >= hos::Version_300) {
|
if (hos::GetVersion() >= hos::Version_3_0_0) {
|
||||||
this->steady_clock_internal_offset_seconds = time::GetStandardSteadyClockInternalOffset().GetSeconds();
|
this->steady_clock_internal_offset_seconds = time::GetStandardSteadyClockInternalOffset().GetSeconds();
|
||||||
} else {
|
} else {
|
||||||
this->steady_clock_internal_offset_seconds = 0;
|
this->steady_clock_internal_offset_seconds = 0;
|
||||||
|
|||||||
@@ -20,14 +20,15 @@ namespace ams::fs {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
Result OpenCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out, const char *path, ncm::ProgramId program_id) {
|
Result OpenCodeFileSystemImpl(CodeInfo *out_code_info, std::unique_ptr<fsa::IFileSystem> *out, const char *path, ncm::ProgramId program_id) {
|
||||||
/* Print a path suitable for the remote service. */
|
/* Print a path suitable for the remote service. */
|
||||||
fssrv::sf::Path sf_path;
|
fssrv::sf::Path sf_path;
|
||||||
R_TRY(FspPathPrintf(std::addressof(sf_path), "%s", path));
|
R_TRY(FspPathPrintf(std::addressof(sf_path), "%s", path));
|
||||||
|
|
||||||
/* Open the filesystem using libnx bindings. */
|
/* Open the filesystem using libnx bindings. */
|
||||||
|
static_assert(sizeof(CodeInfo) == sizeof(::FsCodeInfo));
|
||||||
::FsFileSystem fs;
|
::FsFileSystem fs;
|
||||||
R_TRY(fsldrOpenCodeFileSystem(program_id.value, sf_path.str, std::addressof(fs)));
|
R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_code_info), program_id.value, sf_path.str, std::addressof(fs)));
|
||||||
|
|
||||||
/* Allocate a new filesystem wrapper. */
|
/* Allocate a new filesystem wrapper. */
|
||||||
auto fsa = std::make_unique<RemoteFileSystem>(fs);
|
auto fsa = std::make_unique<RemoteFileSystem>(fs);
|
||||||
@@ -61,12 +62,12 @@ namespace ams::fs {
|
|||||||
return OpenPackageFileSystemImpl(out, sf_path.str);
|
return OpenPackageFileSystemImpl(out, sf_path.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpenSdCardCodeOrCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out, const char *path, ncm::ProgramId program_id) {
|
Result OpenSdCardCodeOrCodeFileSystemImpl(CodeInfo *out_code_info, std::unique_ptr<fsa::IFileSystem> *out, const char *path, ncm::ProgramId program_id) {
|
||||||
/* If we can open an sd card code fs, use it. */
|
/* If we can open an sd card code fs, use it. */
|
||||||
R_SUCCEED_IF(R_SUCCEEDED(OpenSdCardCodeFileSystemImpl(out, program_id)));
|
R_SUCCEED_IF(R_SUCCEEDED(OpenSdCardCodeFileSystemImpl(out, program_id)));
|
||||||
|
|
||||||
/* Otherwise, fall back to a normal code fs. */
|
/* Otherwise, fall back to a normal code fs. */
|
||||||
return OpenCodeFileSystemImpl(out, path, program_id);
|
return OpenCodeFileSystemImpl(out_code_info, out, path, program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpenHblCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out) {
|
Result OpenHblCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out) {
|
||||||
@@ -226,7 +227,7 @@ namespace ams::fs {
|
|||||||
public:
|
public:
|
||||||
AtmosphereCodeFileSystem() : initialized(false) { /* ... */ }
|
AtmosphereCodeFileSystem() : initialized(false) { /* ... */ }
|
||||||
|
|
||||||
Result Initialize(const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific) {
|
Result Initialize(CodeInfo *out_code_info, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific) {
|
||||||
AMS_ABORT_UNLESS(!this->initialized);
|
AMS_ABORT_UNLESS(!this->initialized);
|
||||||
|
|
||||||
/* If we're hbl, we need to open a hbl fs. */
|
/* If we're hbl, we need to open a hbl fs. */
|
||||||
@@ -238,7 +239,7 @@ namespace ams::fs {
|
|||||||
|
|
||||||
/* Open the code filesystem. */
|
/* Open the code filesystem. */
|
||||||
std::unique_ptr<fsa::IFileSystem> fsa;
|
std::unique_ptr<fsa::IFileSystem> fsa;
|
||||||
R_TRY(OpenSdCardCodeOrCodeFileSystemImpl(std::addressof(fsa), path, program_id));
|
R_TRY(OpenSdCardCodeOrCodeFileSystemImpl(out_code_info, std::addressof(fsa), path, program_id));
|
||||||
this->code_fs.emplace(std::move(fsa), program_id, is_specific);
|
this->code_fs.emplace(std::move(fsa), program_id, is_specific);
|
||||||
|
|
||||||
this->program_id = program_id;
|
this->program_id = program_id;
|
||||||
@@ -274,7 +275,10 @@ namespace ams::fs {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MountCode(const char *name, const char *path, ncm::ProgramId program_id) {
|
Result MountCode(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id) {
|
||||||
|
/* Clear the output. */
|
||||||
|
std::memset(out, 0, sizeof(*out));
|
||||||
|
|
||||||
/* Validate the mount name. */
|
/* Validate the mount name. */
|
||||||
R_TRY(impl::CheckMountName(name));
|
R_TRY(impl::CheckMountName(name));
|
||||||
|
|
||||||
@@ -283,13 +287,16 @@ namespace ams::fs {
|
|||||||
|
|
||||||
/* Open the code file system. */
|
/* Open the code file system. */
|
||||||
std::unique_ptr<fsa::IFileSystem> fsa;
|
std::unique_ptr<fsa::IFileSystem> fsa;
|
||||||
R_TRY(OpenCodeFileSystemImpl(std::addressof(fsa), path, program_id));
|
R_TRY(OpenCodeFileSystemImpl(out, std::addressof(fsa), path, program_id));
|
||||||
|
|
||||||
/* Register. */
|
/* Register. */
|
||||||
return fsa::Register(name, std::move(fsa));
|
return fsa::Register(name, std::move(fsa));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MountCodeForAtmosphereWithRedirection(const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific) {
|
Result MountCodeForAtmosphereWithRedirection(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific) {
|
||||||
|
/* Clear the output. */
|
||||||
|
std::memset(out, 0, sizeof(*out));
|
||||||
|
|
||||||
/* Validate the mount name. */
|
/* Validate the mount name. */
|
||||||
R_TRY(impl::CheckMountName(name));
|
R_TRY(impl::CheckMountName(name));
|
||||||
|
|
||||||
@@ -301,13 +308,16 @@ namespace ams::fs {
|
|||||||
R_UNLESS(ams_code_fs != nullptr, fs::ResultAllocationFailureInCodeA());
|
R_UNLESS(ams_code_fs != nullptr, fs::ResultAllocationFailureInCodeA());
|
||||||
|
|
||||||
/* Initialize the code file system. */
|
/* Initialize the code file system. */
|
||||||
R_TRY(ams_code_fs->Initialize(path, program_id, is_hbl, is_specific));
|
R_TRY(ams_code_fs->Initialize(out, path, program_id, is_hbl, is_specific));
|
||||||
|
|
||||||
/* Register. */
|
/* Register. */
|
||||||
return fsa::Register(name, std::move(ams_code_fs));
|
return fsa::Register(name, std::move(ams_code_fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MountCodeForAtmosphere(const char *name, const char *path, ncm::ProgramId program_id) {
|
Result MountCodeForAtmosphere(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id) {
|
||||||
|
/* Clear the output. */
|
||||||
|
std::memset(out, 0, sizeof(*out));
|
||||||
|
|
||||||
/* Validate the mount name. */
|
/* Validate the mount name. */
|
||||||
R_TRY(impl::CheckMountName(name));
|
R_TRY(impl::CheckMountName(name));
|
||||||
|
|
||||||
@@ -316,7 +326,7 @@ namespace ams::fs {
|
|||||||
|
|
||||||
/* Open the code file system. */
|
/* Open the code file system. */
|
||||||
std::unique_ptr<fsa::IFileSystem> fsa;
|
std::unique_ptr<fsa::IFileSystem> fsa;
|
||||||
R_TRY(OpenSdCardCodeOrCodeFileSystemImpl(std::addressof(fsa), path, program_id));
|
R_TRY(OpenSdCardCodeOrCodeFileSystemImpl(out, std::addressof(fsa), path, program_id));
|
||||||
|
|
||||||
/* Create a wrapper fs. */
|
/* Create a wrapper fs. */
|
||||||
auto wrap_fsa = std::make_unique<SdCardRedirectionCodeFileSystem>(std::move(fsa), program_id, false);
|
auto wrap_fsa = std::make_unique<SdCardRedirectionCodeFileSystem>(std::move(fsa), program_id, false);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace ams::fs {
|
|||||||
bool IsSignedSystemPartitionOnSdCardValidDeprecated() {
|
bool IsSignedSystemPartitionOnSdCardValidDeprecated() {
|
||||||
/* Ensure we only call with correct version. */
|
/* Ensure we only call with correct version. */
|
||||||
auto version = hos::GetVersion();
|
auto version = hos::GetVersion();
|
||||||
AMS_ABORT_UNLESS(hos::Version_400 <= version && version < hos::Version_800);
|
AMS_ABORT_UNLESS(hos::Version_4_0_0 <= version && version < hos::Version_8_0_0);
|
||||||
|
|
||||||
/* Check that the partition is valid. */
|
/* Check that the partition is valid. */
|
||||||
bool is_valid;
|
bool is_valid;
|
||||||
|
|||||||
@@ -37,37 +37,41 @@ namespace ams::hos {
|
|||||||
|
|
||||||
switch (exosphere::GetApiInfo().GetTargetFirmware()) {
|
switch (exosphere::GetApiInfo().GetTargetFirmware()) {
|
||||||
case exosphere::TargetFirmware_100:
|
case exosphere::TargetFirmware_100:
|
||||||
g_hos_version = hos::Version_100;
|
g_hos_version = hos::Version_1_0_0;
|
||||||
break;
|
break;
|
||||||
case exosphere::TargetFirmware_200:
|
case exosphere::TargetFirmware_200:
|
||||||
g_hos_version = hos::Version_200;
|
g_hos_version = hos::Version_2_0_0;
|
||||||
break;
|
break;
|
||||||
case exosphere::TargetFirmware_300:
|
case exosphere::TargetFirmware_300:
|
||||||
g_hos_version = hos::Version_300;
|
g_hos_version = hos::Version_3_0_0;
|
||||||
break;
|
break;
|
||||||
case exosphere::TargetFirmware_400:
|
case exosphere::TargetFirmware_400:
|
||||||
g_hos_version = hos::Version_400;
|
g_hos_version = hos::Version_4_0_0;
|
||||||
break;
|
break;
|
||||||
case exosphere::TargetFirmware_500:
|
case exosphere::TargetFirmware_500:
|
||||||
g_hos_version = hos::Version_500;
|
g_hos_version = hos::Version_5_0_0;
|
||||||
break;
|
break;
|
||||||
case exosphere::TargetFirmware_600:
|
case exosphere::TargetFirmware_600:
|
||||||
case exosphere::TargetFirmware_620:
|
case exosphere::TargetFirmware_620:
|
||||||
g_hos_version = hos::Version_600;
|
g_hos_version = hos::Version_6_0_0;
|
||||||
break;
|
break;
|
||||||
case exosphere::TargetFirmware_700:
|
case exosphere::TargetFirmware_700:
|
||||||
g_hos_version = hos::Version_700;
|
g_hos_version = hos::Version_7_0_0;
|
||||||
break;
|
break;
|
||||||
case exosphere::TargetFirmware_800:
|
case exosphere::TargetFirmware_800:
|
||||||
g_hos_version = hos::Version_800;
|
g_hos_version = hos::Version_8_0_0;
|
||||||
break;
|
break;
|
||||||
case exosphere::TargetFirmware_810:
|
case exosphere::TargetFirmware_810:
|
||||||
g_hos_version = hos::Version_810;
|
g_hos_version = hos::Version_8_1_0;
|
||||||
break;
|
break;
|
||||||
case exosphere::TargetFirmware_900:
|
case exosphere::TargetFirmware_900:
|
||||||
g_hos_version = hos::Version_900;
|
g_hos_version = hos::Version_9_0_0;
|
||||||
|
break;
|
||||||
case exosphere::TargetFirmware_910:
|
case exosphere::TargetFirmware_910:
|
||||||
g_hos_version = hos::Version_910;
|
g_hos_version = hos::Version_9_1_0;
|
||||||
|
break;
|
||||||
|
case exosphere::TargetFirmware_1000:
|
||||||
|
g_hos_version = hos::Version_10_0_0;
|
||||||
break;
|
break;
|
||||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
@@ -85,60 +89,65 @@ namespace ams::hos {
|
|||||||
void SetVersionForLibnx() {
|
void SetVersionForLibnx() {
|
||||||
u32 major = 0, minor = 0, micro = 0;
|
u32 major = 0, minor = 0, micro = 0;
|
||||||
switch (hos::GetVersion()) {
|
switch (hos::GetVersion()) {
|
||||||
case hos::Version_100:
|
case hos::Version_1_0_0:
|
||||||
major = 1;
|
major = 1;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
break;
|
break;
|
||||||
case hos::Version_200:
|
case hos::Version_2_0_0:
|
||||||
major = 2;
|
major = 2;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
break;
|
break;
|
||||||
case hos::Version_300:
|
case hos::Version_3_0_0:
|
||||||
major = 3;
|
major = 3;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
break;
|
break;
|
||||||
case hos::Version_400:
|
case hos::Version_4_0_0:
|
||||||
major = 4;
|
major = 4;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
break;
|
break;
|
||||||
case hos::Version_500:
|
case hos::Version_5_0_0:
|
||||||
major = 5;
|
major = 5;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
break;
|
break;
|
||||||
case hos::Version_600:
|
case hos::Version_6_0_0:
|
||||||
major = 6;
|
major = 6;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
break;
|
break;
|
||||||
case hos::Version_700:
|
case hos::Version_7_0_0:
|
||||||
major = 7;
|
major = 7;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
break;
|
break;
|
||||||
case hos::Version_800:
|
case hos::Version_8_0_0:
|
||||||
major = 8;
|
major = 8;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
break;
|
break;
|
||||||
case hos::Version_810:
|
case hos::Version_8_1_0:
|
||||||
major = 8;
|
major = 8;
|
||||||
minor = 1;
|
minor = 1;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
break;
|
break;
|
||||||
case hos::Version_900:
|
case hos::Version_9_0_0:
|
||||||
major = 9;
|
major = 9;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
case hos::Version_910:
|
case hos::Version_9_1_0:
|
||||||
major = 9;
|
major = 9;
|
||||||
minor = 1;
|
minor = 1;
|
||||||
micro = 0;
|
micro = 0;
|
||||||
break;
|
break;
|
||||||
|
case hos::Version_10_0_0:
|
||||||
|
major = 10;
|
||||||
|
minor = 0;
|
||||||
|
micro = 0;
|
||||||
|
break;
|
||||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
hosversionSet(MAKEHOSVERSION(major, minor, micro));
|
hosversionSet(MAKEHOSVERSION(major, minor, micro));
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ namespace ams::ldr::pm {
|
|||||||
return ldrPmAtmosphereGetProgramInfo(reinterpret_cast<LoaderProgramInfo *>(out), reinterpret_cast<CfgOverrideStatus *>(out_status), reinterpret_cast<const NcmProgramLocation *>(&loc));
|
return ldrPmAtmosphereGetProgramInfo(reinterpret_cast<LoaderProgramInfo *>(out), reinterpret_cast<CfgOverrideStatus *>(out_status), reinterpret_cast<const NcmProgramLocation *>(&loc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result SetEnabledProgramVerification(bool enabled) {
|
||||||
|
return ldrPmSetEnabledProgramVerification(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
Result AtmospherePinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) {
|
Result AtmospherePinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) {
|
||||||
static_assert(sizeof(*out) == sizeof(u64), "PinId definition!");
|
static_assert(sizeof(*out) == sizeof(u64), "PinId definition!");
|
||||||
static_assert(sizeof(status) == sizeof(CfgOverrideStatus), "CfgOverrideStatus definition!");
|
static_assert(sizeof(status) == sizeof(CfgOverrideStatus), "CfgOverrideStatus definition!");
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace ams::lr {
|
|||||||
/* Storage for RegisteredData entries by data id. */
|
/* Storage for RegisteredData entries by data id. */
|
||||||
RegisteredStorages<ncm::DataId, 0x800> registered_storages;
|
RegisteredStorages<ncm::DataId, 0x800> registered_storages;
|
||||||
public:
|
public:
|
||||||
AddOnContentLocationResolverImpl() : registered_storages(hos::GetVersion() < hos::Version_900 ? 0x800 : 0x2) { /* ... */ }
|
AddOnContentLocationResolverImpl() : registered_storages(hos::GetVersion() < hos::Version_9_0_0 ? 0x800 : 0x2) { /* ... */ }
|
||||||
|
|
||||||
/* Actual commands. */
|
/* Actual commands. */
|
||||||
virtual Result ResolveAddOnContentPath(sf::Out<Path> out, ncm::DataId id) override;
|
virtual Result ResolveAddOnContentPath(sf::Out<Path> out, ncm::DataId id) override;
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace ams::lr {
|
|||||||
|
|
||||||
Result RegisteredLocationResolverImpl::RefreshImpl(const ncm::ProgramId *excluding_ids, size_t num_ids) {
|
Result RegisteredLocationResolverImpl::RefreshImpl(const ncm::ProgramId *excluding_ids, size_t num_ids) {
|
||||||
/* On < 9.0.0, exclusion lists were not supported yet, so simply clear and return. */
|
/* On < 9.0.0, exclusion lists were not supported yet, so simply clear and return. */
|
||||||
if (hos::GetVersion() < hos::Version_900) {
|
if (hos::GetVersion() < hos::Version_9_0_0) {
|
||||||
this->ClearRedirections();
|
this->ClearRedirections();
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace ams::lr {
|
|||||||
static_assert(MaxRegisteredLocations >= MaxRegisteredLocationsDeprecated);
|
static_assert(MaxRegisteredLocations >= MaxRegisteredLocationsDeprecated);
|
||||||
private:
|
private:
|
||||||
static ALWAYS_INLINE size_t GetMaxRegisteredLocations() {
|
static ALWAYS_INLINE size_t GetMaxRegisteredLocations() {
|
||||||
if (hos::GetVersion() >= hos::Version_900) {
|
if (hos::GetVersion() >= hos::Version_9_0_0) {
|
||||||
return MaxRegisteredLocations;
|
return MaxRegisteredLocations;
|
||||||
} else {
|
} else {
|
||||||
return MaxRegisteredLocationsDeprecated;
|
return MaxRegisteredLocationsDeprecated;
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ namespace ams::map {
|
|||||||
R_TRY(svcGetInfo(&out->heap_size, InfoType_HeapRegionSize, process_h, 0));
|
R_TRY(svcGetInfo(&out->heap_size, InfoType_HeapRegionSize, process_h, 0));
|
||||||
R_TRY(svcGetInfo(&out->alias_base, InfoType_AliasRegionAddress, process_h, 0));
|
R_TRY(svcGetInfo(&out->alias_base, InfoType_AliasRegionAddress, process_h, 0));
|
||||||
R_TRY(svcGetInfo(&out->alias_size, InfoType_AliasRegionSize, process_h, 0));
|
R_TRY(svcGetInfo(&out->alias_size, InfoType_AliasRegionSize, process_h, 0));
|
||||||
if (hos::GetVersion() >= hos::Version_200) {
|
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||||
R_TRY(svcGetInfo(&out->aslr_base, InfoType_AslrRegionAddress, process_h, 0));
|
R_TRY(svcGetInfo(&out->aslr_base, InfoType_AslrRegionAddress, process_h, 0));
|
||||||
R_TRY(svcGetInfo(&out->aslr_size, InfoType_AslrRegionSize, process_h, 0));
|
R_TRY(svcGetInfo(&out->aslr_size, InfoType_AslrRegionSize, process_h, 0));
|
||||||
} else {
|
} else {
|
||||||
@@ -184,7 +184,7 @@ namespace ams::map {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result LocateMappableSpace(uintptr_t *out_address, size_t size) {
|
Result LocateMappableSpace(uintptr_t *out_address, size_t size) {
|
||||||
if (hos::GetVersion() >= hos::Version_200) {
|
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||||
return LocateMappableSpaceModern(out_address, size);
|
return LocateMappableSpaceModern(out_address, size);
|
||||||
} else {
|
} else {
|
||||||
return LocateMappableSpaceDeprecated(out_address, size);
|
return LocateMappableSpaceDeprecated(out_address, size);
|
||||||
@@ -192,7 +192,7 @@ namespace ams::map {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result MapCodeMemoryInProcess(MappedCodeMemory &out_mcm, Handle process_handle, uintptr_t base_address, size_t size) {
|
Result MapCodeMemoryInProcess(MappedCodeMemory &out_mcm, Handle process_handle, uintptr_t base_address, size_t size) {
|
||||||
if (hos::GetVersion() >= hos::Version_200) {
|
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||||
return MapCodeMemoryInProcessModern(out_mcm, process_handle, base_address, size);
|
return MapCodeMemoryInProcessModern(out_mcm, process_handle, base_address, size);
|
||||||
} else {
|
} else {
|
||||||
return MapCodeMemoryInProcessDeprecated(out_mcm, process_handle, base_address, size);
|
return MapCodeMemoryInProcessDeprecated(out_mcm, process_handle, base_address, size);
|
||||||
|
|||||||
@@ -101,12 +101,12 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
/* Deprecated API. */
|
/* Deprecated API. */
|
||||||
Result CloseContentStorageForcibly(StorageId storage_id) {
|
Result CloseContentStorageForcibly(StorageId storage_id) {
|
||||||
AMS_ABORT_UNLESS(hos::GetVersion() == hos::Version_100);
|
AMS_ABORT_UNLESS(hos::GetVersion() == hos::Version_1_0_0);
|
||||||
return g_content_manager->CloseContentStorageForcibly(storage_id);
|
return g_content_manager->CloseContentStorageForcibly(storage_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CloseContentMetaDatabaseForcibly(StorageId storage_id) {
|
Result CloseContentMetaDatabaseForcibly(StorageId storage_id) {
|
||||||
AMS_ABORT_UNLESS(hos::GetVersion() == hos::Version_100);
|
AMS_ABORT_UNLESS(hos::GetVersion() == hos::Version_1_0_0);
|
||||||
return g_content_manager->CloseContentMetaDatabaseForcibly(storage_id);
|
return g_content_manager->CloseContentMetaDatabaseForcibly(storage_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,11 +113,11 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
ALWAYS_INLINE bool IsSignedSystemPartitionOnSdCardValid(const char *bis_mount_name) {
|
ALWAYS_INLINE bool IsSignedSystemPartitionOnSdCardValid(const char *bis_mount_name) {
|
||||||
/* Signed system partition should never be checked on < 4.0.0, as it did not exist before then. */
|
/* Signed system partition should never be checked on < 4.0.0, as it did not exist before then. */
|
||||||
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_400);
|
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_4_0_0);
|
||||||
|
|
||||||
/* If we're importing from system on SD, make sure that the signed system partition is valid. */
|
/* If we're importing from system on SD, make sure that the signed system partition is valid. */
|
||||||
const auto version = hos::GetVersion();
|
const auto version = hos::GetVersion();
|
||||||
if (version >= hos::Version_800) {
|
if (version >= hos::Version_8_0_0) {
|
||||||
/* On >= 8.0.0, a simpler method was added to check validity. */
|
/* On >= 8.0.0, a simpler method was added to check validity. */
|
||||||
/* This also works on < 4.0.0 (though the system partition will never be on-sd there), */
|
/* This also works on < 4.0.0 (though the system partition will never be on-sd there), */
|
||||||
/* and so this will always return false. */
|
/* and so this will always return false. */
|
||||||
@@ -156,7 +156,7 @@ namespace ams::ncm {
|
|||||||
R_CATCH(fs::ResultTargetNotFound) {
|
R_CATCH(fs::ResultTargetNotFound) {
|
||||||
/* On 1.0.0, not all flags existed. Mask when appropriate. */
|
/* On 1.0.0, not all flags existed. Mask when appropriate. */
|
||||||
constexpr u32 SaveDataFlags100Mask = fs::SaveDataFlags_KeepAfterResettingSystemSaveData;
|
constexpr u32 SaveDataFlags100Mask = fs::SaveDataFlags_KeepAfterResettingSystemSaveData;
|
||||||
const u32 flags = (hos::GetVersion() >= hos::Version_200) ? (info.flags) : (info.flags & SaveDataFlags100Mask);
|
const u32 flags = (hos::GetVersion() >= hos::Version_2_0_0) ? (info.flags) : (info.flags & SaveDataFlags100Mask);
|
||||||
R_TRY(fs::CreateSystemSaveData(info.space_id, info.id, OwnerId, info.size, info.journal_size, flags));
|
R_TRY(fs::CreateSystemSaveData(info.space_id, info.id, OwnerId, info.size, info.journal_size, flags));
|
||||||
R_TRY(fs::MountSystemSaveData(mount_name, info.space_id, info.id));
|
R_TRY(fs::MountSystemSaveData(mount_name, info.space_id, info.id));
|
||||||
}
|
}
|
||||||
@@ -275,7 +275,7 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result ContentManagerImpl::BuildContentMetaDatabase(StorageId storage_id) {
|
Result ContentManagerImpl::BuildContentMetaDatabase(StorageId storage_id) {
|
||||||
if (hos::GetVersion() <= hos::Version_400) {
|
if (hos::GetVersion() <= hos::Version_4_0_0) {
|
||||||
/* Temporarily activate the database. */
|
/* Temporarily activate the database. */
|
||||||
R_TRY(this->ActivateContentMetaDatabase(storage_id));
|
R_TRY(this->ActivateContentMetaDatabase(storage_id));
|
||||||
ON_SCOPE_EXIT { this->InactivateContentMetaDatabase(storage_id); };
|
ON_SCOPE_EXIT { this->InactivateContentMetaDatabase(storage_id); };
|
||||||
@@ -357,7 +357,7 @@ namespace ams::ncm {
|
|||||||
/* Ensure correct flags on the BuiltInSystem save data. */
|
/* Ensure correct flags on the BuiltInSystem save data. */
|
||||||
/* NOTE: Nintendo does not check this succeeds, and it does on older system versions. */
|
/* NOTE: Nintendo does not check this succeeds, and it does on older system versions. */
|
||||||
/* We will not check the error, either, even though this kind of defeats the call's purpose. */
|
/* We will not check the error, either, even though this kind of defeats the call's purpose. */
|
||||||
if (hos::GetVersion() >= hos::Version_200) {
|
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||||
EnsureBuiltInSystemSaveDataFlags();
|
EnsureBuiltInSystemSaveDataFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +472,7 @@ namespace ams::ncm {
|
|||||||
ContentStorageRoot *root;
|
ContentStorageRoot *root;
|
||||||
R_TRY(this->GetContentStorageRoot(std::addressof(root), storage_id));
|
R_TRY(this->GetContentStorageRoot(std::addressof(root), storage_id));
|
||||||
|
|
||||||
if (hos::GetVersion() >= hos::Version_200) {
|
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||||
/* Obtain the content storage if already active. */
|
/* Obtain the content storage if already active. */
|
||||||
R_UNLESS(root->content_storage, GetContentStorageNotActiveResult(storage_id));
|
R_UNLESS(root->content_storage, GetContentStorageNotActiveResult(storage_id));
|
||||||
} else {
|
} else {
|
||||||
@@ -493,7 +493,7 @@ namespace ams::ncm {
|
|||||||
ContentMetaDatabaseRoot *root;
|
ContentMetaDatabaseRoot *root;
|
||||||
R_TRY(this->GetContentMetaDatabaseRoot(&root, storage_id));
|
R_TRY(this->GetContentMetaDatabaseRoot(&root, storage_id));
|
||||||
|
|
||||||
if (hos::GetVersion() >= hos::Version_200) {
|
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||||
/* Obtain the content meta database if already active. */
|
/* Obtain the content meta database if already active. */
|
||||||
R_UNLESS(root->content_meta_database, GetContentMetaDatabaseNotActiveResult(storage_id));
|
R_UNLESS(root->content_meta_database, GetContentMetaDatabaseNotActiveResult(storage_id));
|
||||||
} else {
|
} else {
|
||||||
@@ -614,7 +614,7 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
if (storage_id == StorageId::GameCard) {
|
if (storage_id == StorageId::GameCard) {
|
||||||
/* Initialize the key value store. */
|
/* Initialize the key value store. */
|
||||||
R_TRY(root->kvs->Initialize(root->max_content_metas, root->memory_resource->Get()));
|
R_TRY(root->kvs->Initialize(root->max_content_metas, root->memory_resource));
|
||||||
|
|
||||||
/* Create an on memory content meta database for game cards. */
|
/* Create an on memory content meta database for game cards. */
|
||||||
root->content_meta_database = std::make_shared<OnMemoryContentMetaDatabaseImpl>(std::addressof(*root->kvs));
|
root->content_meta_database = std::make_shared<OnMemoryContentMetaDatabaseImpl>(std::addressof(*root->kvs));
|
||||||
@@ -626,7 +626,7 @@ namespace ams::ncm {
|
|||||||
auto mount_guard = SCOPE_GUARD { fs::Unmount(root->mount_name); };
|
auto mount_guard = SCOPE_GUARD { fs::Unmount(root->mount_name); };
|
||||||
|
|
||||||
/* Initialize and load the key value store from the filesystem. */
|
/* Initialize and load the key value store from the filesystem. */
|
||||||
R_TRY(root->kvs->Initialize(root->path, root->max_content_metas, root->memory_resource->Get()));
|
R_TRY(root->kvs->Initialize(root->path, root->max_content_metas, root->memory_resource));
|
||||||
R_TRY(root->kvs->Load());
|
R_TRY(root->kvs->Load());
|
||||||
|
|
||||||
/* Create the content meta database. */
|
/* Create the content meta database. */
|
||||||
@@ -665,4 +665,36 @@ namespace ams::ncm {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ContentManagerImpl::GetMemoryReport(sf::Out<MemoryReport> out) {
|
||||||
|
/* Populate content meta resource states. */
|
||||||
|
MemoryReport report = {
|
||||||
|
.system_content_meta_resource_state = {
|
||||||
|
.peak_total_alloc_size = g_system_content_meta_memory_resource.GetPeakTotalAllocationSize(),
|
||||||
|
.peak_alloc_size = g_system_content_meta_memory_resource.GetPeakAllocationSize(),
|
||||||
|
.allocatable_size = g_system_content_meta_memory_resource.GetAllocator()->GetAllocatableSize(),
|
||||||
|
.total_free_size = g_system_content_meta_memory_resource.GetAllocator()->GetTotalFreeSize(),
|
||||||
|
},
|
||||||
|
.sd_and_user_content_meta_resource_state {
|
||||||
|
.peak_total_alloc_size = g_sd_and_user_content_meta_memory_resource.GetPeakTotalAllocationSize(),
|
||||||
|
.peak_alloc_size = g_sd_and_user_content_meta_memory_resource.GetPeakAllocationSize(),
|
||||||
|
.allocatable_size = g_sd_and_user_content_meta_memory_resource.GetAllocator()->GetAllocatableSize(),
|
||||||
|
.total_free_size = g_sd_and_user_content_meta_memory_resource.GetAllocator()->GetTotalFreeSize(),
|
||||||
|
},
|
||||||
|
.gamecard_content_meta_resource_state {
|
||||||
|
.peak_total_alloc_size = g_gamecard_content_meta_memory_resource.GetPeakTotalAllocationSize(),
|
||||||
|
.peak_alloc_size = g_gamecard_content_meta_memory_resource.GetPeakAllocationSize(),
|
||||||
|
.allocatable_size = g_gamecard_content_meta_memory_resource.GetAllocator()->GetAllocatableSize(),
|
||||||
|
.total_free_size = g_gamecard_content_meta_memory_resource.GetAllocator()->GetTotalFreeSize(),
|
||||||
|
},
|
||||||
|
.heap_resource_state = {},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Populate heap memory resource state. */
|
||||||
|
GetHeapState().GetMemoryResourceState(std::addressof(report.heap_resource_state));
|
||||||
|
|
||||||
|
/* Output the report. */
|
||||||
|
out.SetValue(report);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ namespace ams::ncm {
|
|||||||
break;
|
break;
|
||||||
case ContentMetaType::Application:
|
case ContentMetaType::Application:
|
||||||
/* As of 9.0.0, applications can be dependent on a specific base application version. */
|
/* As of 9.0.0, applications can be dependent on a specific base application version. */
|
||||||
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_900);
|
AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_9_0_0);
|
||||||
required_version = reader.GetExtendedHeader<ApplicationMetaExtendedHeader>()->required_application_version;
|
required_version = reader.GetExtendedHeader<ApplicationMetaExtendedHeader>()->required_application_version;
|
||||||
break;
|
break;
|
||||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
@@ -440,4 +440,47 @@ namespace ams::ncm {
|
|||||||
return this->GetContentIdImpl(out_content_id.GetPointer(), key, type, std::make_optional(id_offset));
|
return this->GetContentIdImpl(out_content_id.GetPointer(), key, type, std::make_optional(id_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ContentMetaDatabaseImpl::GetCount(sf::Out<u32> out_count) {
|
||||||
|
R_TRY(this->EnsureEnabled());
|
||||||
|
out_count.SetValue(this->kvs->GetCount());
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ContentMetaDatabaseImpl::GetOwnerApplicationId(sf::Out<ApplicationId> out_id, const ContentMetaKey &key) {
|
||||||
|
R_TRY(this->EnsureEnabled());
|
||||||
|
|
||||||
|
/* Ensure this type of key has an owner. */
|
||||||
|
R_UNLESS(key.type == ContentMetaType::Application || key.type == ContentMetaType::Patch || key.type == ContentMetaType::AddOnContent, ncm::ResultInvalidContentMetaKey());
|
||||||
|
|
||||||
|
/* Applications are their own owner. */
|
||||||
|
if (key.type == ContentMetaType::Application) {
|
||||||
|
out_id.SetValue({key.id});
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Obtain the content meta for the key. */
|
||||||
|
const void *meta;
|
||||||
|
size_t meta_size;
|
||||||
|
R_TRY(this->GetContentMetaPointer(&meta, &meta_size, key));
|
||||||
|
|
||||||
|
/* Create a reader. */
|
||||||
|
ContentMetaReader reader(meta, meta_size);
|
||||||
|
|
||||||
|
/* Get the owner application id. */
|
||||||
|
ApplicationId owner_application_id;
|
||||||
|
switch (key.type) {
|
||||||
|
case ContentMetaType::Patch:
|
||||||
|
owner_application_id = reader.GetExtendedHeader<PatchMetaExtendedHeader>()->application_id;
|
||||||
|
break;
|
||||||
|
case ContentMetaType::AddOnContent:
|
||||||
|
owner_application_id = reader.GetExtendedHeader<AddOnContentMetaExtendedHeader>()->application_id;
|
||||||
|
break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the output value. */
|
||||||
|
out_id.SetValue(owner_application_id);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ namespace ams::ncm {
|
|||||||
virtual Result GetAttributes(sf::Out<u8> out_attributes, const ContentMetaKey &key) override;
|
virtual Result GetAttributes(sf::Out<u8> out_attributes, const ContentMetaKey &key) override;
|
||||||
virtual Result GetRequiredApplicationVersion(sf::Out<u32> out_version, const ContentMetaKey &key) override;
|
virtual Result GetRequiredApplicationVersion(sf::Out<u32> out_version, const ContentMetaKey &key) override;
|
||||||
virtual Result GetContentIdByTypeAndIdOffset(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) override;
|
virtual Result GetContentIdByTypeAndIdOffset(sf::Out<ContentId> out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) override;
|
||||||
|
virtual Result GetCount(sf::Out<u32> out_count) override;
|
||||||
|
virtual Result GetOwnerApplicationId(sf::Out<ApplicationId> out_id, const ContentMetaKey &key) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ namespace ams::ncm {
|
|||||||
R_SUCCEED_IF(max_level <= 0);
|
R_SUCCEED_IF(max_level <= 0);
|
||||||
|
|
||||||
/* On 1.0.0, NotRequireFileSize was not a valid open mode. */
|
/* On 1.0.0, NotRequireFileSize was not a valid open mode. */
|
||||||
const auto open_dir_mode = hos::GetVersion() >= hos::Version_200 ? (fs::OpenDirectoryMode_All | fs::OpenDirectoryMode_NotRequireFileSize) : (fs::OpenDirectoryMode_All);
|
const auto open_dir_mode = hos::GetVersion() >= hos::Version_2_0_0 ? (fs::OpenDirectoryMode_All | fs::OpenDirectoryMode_NotRequireFileSize) : (fs::OpenDirectoryMode_All);
|
||||||
|
|
||||||
/* Retry traversal upon request. */
|
/* Retry traversal upon request. */
|
||||||
bool retry_dir_read = true;
|
bool retry_dir_read = true;
|
||||||
@@ -153,7 +153,7 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result CleanDirectoryRecursively(const PathString &path) {
|
Result CleanDirectoryRecursively(const PathString &path) {
|
||||||
if (hos::GetVersion() >= hos::Version_300) {
|
if (hos::GetVersion() >= hos::Version_3_0_0) {
|
||||||
R_TRY(fs::CleanDirectoryRecursively(path));
|
R_TRY(fs::CleanDirectoryRecursively(path));
|
||||||
} else {
|
} else {
|
||||||
/* CleanDirectoryRecursively didn't exist on < 3.0.0, so we will polyfill it. */
|
/* CleanDirectoryRecursively didn't exist on < 3.0.0, so we will polyfill it. */
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Result GetRightsId(ncm::RightsId *out_rights_id, const Path &path) {
|
static Result GetRightsId(ncm::RightsId *out_rights_id, const Path &path) {
|
||||||
if (hos::GetVersion() >= hos::Version_300) {
|
if (hos::GetVersion() >= hos::Version_3_0_0) {
|
||||||
R_TRY(fs::GetRightsId(std::addressof(out_rights_id->id), std::addressof(out_rights_id->key_generation), path.str));
|
R_TRY(fs::GetRightsId(std::addressof(out_rights_id->id), std::addressof(out_rights_id->key_generation), path.str));
|
||||||
} else {
|
} else {
|
||||||
R_TRY(fs::GetRightsId(std::addressof(out_rights_id->id), path.str));
|
R_TRY(fs::GetRightsId(std::addressof(out_rights_id->id), path.str));
|
||||||
|
|||||||
51
libraries/libstratosphere/source/ncm/ncm_memory_report.cpp
Normal file
51
libraries/libstratosphere/source/ncm/ncm_memory_report.cpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::ncm {
|
||||||
|
|
||||||
|
void HeapState::Initialize(lmem::HeapHandle heap_handle) {
|
||||||
|
std::scoped_lock lk(this->mutex);
|
||||||
|
this->heap_handle = heap_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeapState::Allocate(size_t size) {
|
||||||
|
std::scoped_lock lk(this->mutex);
|
||||||
|
this->total_alloc_size += size;
|
||||||
|
this->peak_total_alloc_size = std::max(this->total_alloc_size, this->peak_total_alloc_size);
|
||||||
|
this->peak_alloc_size = std::max(size, this->peak_alloc_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeapState::Free(size_t size) {
|
||||||
|
std::scoped_lock lk(this->mutex);
|
||||||
|
this->total_alloc_size -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeapState::GetMemoryResourceState(MemoryResourceState *out) {
|
||||||
|
*out = {};
|
||||||
|
std::scoped_lock lk(this->mutex);
|
||||||
|
out->peak_total_alloc_size = this->peak_total_alloc_size;
|
||||||
|
out->peak_alloc_size = this->peak_alloc_size;
|
||||||
|
out->total_free_size = lmem::GetExpHeapTotalFreeSize(this->heap_handle);
|
||||||
|
out->allocatable_size = lmem::GetExpHeapAllocatableSize(this->heap_handle, alignof(s32));
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapState &GetHeapState() {
|
||||||
|
static HeapState s_heap_state = {};
|
||||||
|
return s_heap_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -89,6 +89,11 @@ namespace ams::ncm {
|
|||||||
virtual Result InvalidateRightsIdCache() override {
|
virtual Result InvalidateRightsIdCache() override {
|
||||||
return ::ncmInvalidateRightsIdCache();
|
return ::ncmInvalidateRightsIdCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Result GetMemoryReport(sf::Out<MemoryReport> out) override {
|
||||||
|
/* TODO: libnx bindings */
|
||||||
|
AMS_ABORT();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,6 +156,16 @@ namespace ams::ncm {
|
|||||||
return ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset(std::addressof(this->srv), Convert(out_content_id.GetPointer()), Convert(key), static_cast<::NcmContentType>(type), id_offset);
|
return ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset(std::addressof(this->srv), Convert(out_content_id.GetPointer()), Convert(key), static_cast<::NcmContentType>(type), id_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Result GetCount(sf::Out<u32> out_count) override {
|
||||||
|
/* TODO: libnx bindings */
|
||||||
|
AMS_ABORT();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Result GetOwnerApplicationId(sf::Out<ApplicationId> out_id, const ContentMetaKey &key) override {
|
||||||
|
/* TODO: libnx bindings */
|
||||||
|
AMS_ABORT();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ namespace ams::os::impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ThreadManagerHorizonImpl::YieldThread() {
|
void ThreadManagerHorizonImpl::YieldThread() {
|
||||||
if (hos::GetVersion() >= hos::Version_400) {
|
if (hos::GetVersion() >= hos::Version_4_0_0) {
|
||||||
svc::SleepThread(svc::YieldType_WithCoreMigration);
|
svc::SleepThread(svc::YieldType_WithCoreMigration);
|
||||||
} else {
|
} else {
|
||||||
svc::SleepThread(svc::YieldType_WithoutCoreMigration);
|
svc::SleepThread(svc::YieldType_WithoutCoreMigration);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace ams::psc {
|
|||||||
R_ABORT_UNLESS(res);
|
R_ABORT_UNLESS(res);
|
||||||
R_UNLESS(this->initialized, psc::ResultNotInitialized());
|
R_UNLESS(this->initialized, psc::ResultNotInitialized());
|
||||||
|
|
||||||
if (hos::GetVersion() >= hos::Version_600) {
|
if (hos::GetVersion() >= hos::Version_6_0_0) {
|
||||||
return this->intf->AcknowledgeEx(state);
|
return this->intf->AcknowledgeEx(state);
|
||||||
} else {
|
} else {
|
||||||
return this->intf->Acknowledge();
|
return this->intf->Acknowledge();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace ams::sf::cmif {
|
|||||||
Result impl::ServiceDispatchTableBase::ProcessMessageImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count) const {
|
Result impl::ServiceDispatchTableBase::ProcessMessageImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count) const {
|
||||||
/* Get versioning info. */
|
/* Get versioning info. */
|
||||||
const auto hos_version = hos::GetVersion();
|
const auto hos_version = hos::GetVersion();
|
||||||
const u32 max_cmif_version = hos_version >= hos::Version_500 ? 1 : 0;
|
const u32 max_cmif_version = hos_version >= hos::Version_5_0_0 ? 1 : 0;
|
||||||
|
|
||||||
/* Parse the CMIF in header. */
|
/* Parse the CMIF in header. */
|
||||||
const CmifInHeader *in_header = reinterpret_cast<const CmifInHeader *>(in_raw_data.GetPointer());
|
const CmifInHeader *in_header = reinterpret_cast<const CmifInHeader *>(in_raw_data.GetPointer());
|
||||||
@@ -60,7 +60,7 @@ namespace ams::sf::cmif {
|
|||||||
Result impl::ServiceDispatchTableBase::ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count) const {
|
Result impl::ServiceDispatchTableBase::ProcessMessageForMitmImpl(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data, const ServiceCommandMeta *entries, const size_t entry_count) const {
|
||||||
/* Get versioning info. */
|
/* Get versioning info. */
|
||||||
const auto hos_version = hos::GetVersion();
|
const auto hos_version = hos::GetVersion();
|
||||||
const u32 max_cmif_version = hos_version >= hos::Version_500 ? 1 : 0;
|
const u32 max_cmif_version = hos_version >= hos::Version_5_0_0 ? 1 : 0;
|
||||||
|
|
||||||
/* Parse the CMIF in header. */
|
/* Parse the CMIF in header. */
|
||||||
const CmifInHeader *in_header = reinterpret_cast<const CmifInHeader *>(in_raw_data.GetPointer());
|
const CmifInHeader *in_header = reinterpret_cast<const CmifInHeader *>(in_raw_data.GetPointer());
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ namespace ams::spl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsDisabledProgramVerification() {
|
||||||
|
u64 val = 0;
|
||||||
|
R_ABORT_UNLESS(splGetConfig(SplConfigItem_DisableProgramVerification, &val));
|
||||||
|
return val != 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsDevelopmentHardware() {
|
bool IsDevelopmentHardware() {
|
||||||
bool is_dev_hardware;
|
bool is_dev_hardware;
|
||||||
R_ABORT_UNLESS(splIsDevelopment(&is_dev_hardware));
|
R_ABORT_UNLESS(splIsDevelopment(&is_dev_hardware));
|
||||||
|
|||||||
@@ -16,11 +16,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
|
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 10
|
#define ATMOSPHERE_RELEASE_VERSION_MINOR 11
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 5
|
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
|
||||||
|
|
||||||
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
|
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
|
||||||
|
|
||||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 9
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 10
|
||||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 2
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
|
||||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
||||||
|
|||||||
@@ -15,20 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_100 1
|
#define ATMOSPHERE_TARGET_FIRMWARE_100 1
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_200 2
|
#define ATMOSPHERE_TARGET_FIRMWARE_200 2
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_300 3
|
#define ATMOSPHERE_TARGET_FIRMWARE_300 3
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_400 4
|
#define ATMOSPHERE_TARGET_FIRMWARE_400 4
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_500 5
|
#define ATMOSPHERE_TARGET_FIRMWARE_500 5
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_600 6
|
#define ATMOSPHERE_TARGET_FIRMWARE_600 6
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_620 7
|
#define ATMOSPHERE_TARGET_FIRMWARE_620 7
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_700 8
|
#define ATMOSPHERE_TARGET_FIRMWARE_700 8
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_800 9
|
#define ATMOSPHERE_TARGET_FIRMWARE_800 9
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_810 10
|
#define ATMOSPHERE_TARGET_FIRMWARE_810 10
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_900 11
|
#define ATMOSPHERE_TARGET_FIRMWARE_900 11
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_910 12
|
#define ATMOSPHERE_TARGET_FIRMWARE_910 12
|
||||||
|
#define ATMOSPHERE_TARGET_FIRMWARE_1000 13
|
||||||
|
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_910
|
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_1000
|
||||||
|
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
|
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
||||||
|
|||||||
@@ -42,6 +42,14 @@ namespace ams::crypto {
|
|||||||
return Rsa2048PssSha256Verifier::Verify(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size, work_buf, work_buf_size);
|
return Rsa2048PssSha256Verifier::Verify(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size, work_buf, work_buf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool VerifyRsa2048PssSha256WithHash(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *hash, size_t hash_size) {
|
||||||
|
return Rsa2048PssSha256Verifier::VerifyWithHash(sig, sig_size, mod, mod_size, exp, exp_size, hash, hash_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VerifyRsa2048PssSha256WithHash(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *hash, size_t hash_size, void *work_buf, size_t work_buf_size) {
|
||||||
|
return Rsa2048PssSha256Verifier::VerifyWithHash(sig, sig_size, mod, mod_size, exp, exp_size, hash, hash_size, work_buf, work_buf_size);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool VerifyRsa4096PssSha256(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *msg, size_t msg_size) {
|
inline bool VerifyRsa4096PssSha256(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *msg, size_t msg_size) {
|
||||||
return Rsa4096PssSha256Verifier::Verify(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size);
|
return Rsa4096PssSha256Verifier::Verify(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size);
|
||||||
}
|
}
|
||||||
@@ -50,4 +58,12 @@ namespace ams::crypto {
|
|||||||
return Rsa4096PssSha256Verifier::Verify(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size, work_buf, work_buf_size);
|
return Rsa4096PssSha256Verifier::Verify(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size, work_buf, work_buf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool VerifyRsa4096PssSha256WithHash(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *hash, size_t hash_size) {
|
||||||
|
return Rsa4096PssSha256Verifier::VerifyWithHash(sig, sig_size, mod, mod_size, exp, exp_size, hash, hash_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VerifyRsa4096PssSha256WithHash(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *hash, size_t hash_size, void *work_buf, size_t work_buf_size) {
|
||||||
|
return Rsa4096PssSha256Verifier::VerifyWithHash(sig, sig_size, mod, mod_size, exp, exp_size, hash, hash_size, work_buf, work_buf_size);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,13 +23,14 @@
|
|||||||
|
|
||||||
namespace ams::crypto {
|
namespace ams::crypto {
|
||||||
|
|
||||||
template<size_t ModulusSize, typename Hash> /* requires HashFunction<Hash> */
|
template<size_t _ModulusSize, typename Hash> /* requires HashFunction<Hash> */
|
||||||
class RsaPssVerifier {
|
class RsaPssVerifier {
|
||||||
NON_COPYABLE(RsaPssVerifier);
|
NON_COPYABLE(RsaPssVerifier);
|
||||||
NON_MOVEABLE(RsaPssVerifier);
|
NON_MOVEABLE(RsaPssVerifier);
|
||||||
public:
|
public:
|
||||||
static constexpr size_t HashSize = Hash::HashSize;
|
static constexpr size_t HashSize = Hash::HashSize;
|
||||||
static constexpr size_t SaltSize = Hash::HashSize;
|
static constexpr size_t SaltSize = Hash::HashSize;
|
||||||
|
static constexpr size_t ModulusSize = _ModulusSize;
|
||||||
static constexpr size_t SignatureSize = ModulusSize;
|
static constexpr size_t SignatureSize = ModulusSize;
|
||||||
static constexpr size_t MaximumExponentSize = 3;
|
static constexpr size_t MaximumExponentSize = 3;
|
||||||
static constexpr size_t RequiredWorkBufferSize = RsaCalculator<ModulusSize, MaximumExponentSize>::RequiredWorkBufferSize;
|
static constexpr size_t RequiredWorkBufferSize = RsaCalculator<ModulusSize, MaximumExponentSize>::RequiredWorkBufferSize;
|
||||||
@@ -70,8 +71,15 @@ namespace ams::crypto {
|
|||||||
u8 message[SignatureSize];
|
u8 message[SignatureSize];
|
||||||
ON_SCOPE_EXIT { ClearMemory(message, sizeof(message)); };
|
ON_SCOPE_EXIT { ClearMemory(message, sizeof(message)); };
|
||||||
|
|
||||||
return this->calculator.ExpMod(message, signature, SignatureSize) &&
|
if (!this->calculator.ExpMod(message, signature, SignatureSize)) {
|
||||||
impl.Verify(message, sizeof(message), std::addressof(this->hash));
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 calc_hash[Hash::HashSize];
|
||||||
|
this->hash.GetHash(calc_hash, sizeof(calc_hash));
|
||||||
|
ON_SCOPE_EXIT { ClearMemory(calc_hash, sizeof(calc_hash)); };
|
||||||
|
|
||||||
|
return impl.Verify(message, sizeof(message), calc_hash, sizeof(calc_hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Verify(const void *signature, size_t size, void *work_buf, size_t work_buf_size) {
|
bool Verify(const void *signature, size_t size, void *work_buf, size_t work_buf_size) {
|
||||||
@@ -83,8 +91,47 @@ namespace ams::crypto {
|
|||||||
u8 message[SignatureSize];
|
u8 message[SignatureSize];
|
||||||
ON_SCOPE_EXIT { ClearMemory(message, sizeof(message)); };
|
ON_SCOPE_EXIT { ClearMemory(message, sizeof(message)); };
|
||||||
|
|
||||||
return this->calculator.ExpMod(message, signature, SignatureSize, work_buf, work_buf_size) &&
|
if (!this->calculator.ExpMod(message, signature, SignatureSize, work_buf, work_buf_size)) {
|
||||||
impl.Verify(message, sizeof(message), std::addressof(this->hash));
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 calc_hash[Hash::HashSize];
|
||||||
|
this->hash.GetHash(calc_hash, sizeof(calc_hash));
|
||||||
|
ON_SCOPE_EXIT { ClearMemory(calc_hash, sizeof(calc_hash)); };
|
||||||
|
|
||||||
|
return impl.Verify(message, sizeof(message), calc_hash, sizeof(calc_hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VerifyWithHash(const void *signature, size_t size, const void *hash, size_t hash_size) {
|
||||||
|
AMS_ASSERT(this->state == State::Initialized);
|
||||||
|
AMS_ASSERT(size == SignatureSize);
|
||||||
|
ON_SCOPE_EXIT { this->state = State::Done; };
|
||||||
|
|
||||||
|
impl::RsaPssImpl<Hash> impl;
|
||||||
|
u8 message[SignatureSize];
|
||||||
|
ON_SCOPE_EXIT { ClearMemory(message, sizeof(message)); };
|
||||||
|
|
||||||
|
if (!this->calculator.ExpMod(message, signature, SignatureSize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return impl.Verify(message, sizeof(message), static_cast<const u8 *>(hash), hash_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VerifyWithHash(const void *signature, size_t size, const void *hash, size_t hash_size, void *work_buf, size_t work_buf_size) {
|
||||||
|
AMS_ASSERT(this->state == State::Initialized);
|
||||||
|
AMS_ASSERT(size == SignatureSize);
|
||||||
|
ON_SCOPE_EXIT { this->state = State::Done; };
|
||||||
|
|
||||||
|
impl::RsaPssImpl<Hash> impl;
|
||||||
|
u8 message[SignatureSize];
|
||||||
|
ON_SCOPE_EXIT { ClearMemory(message, sizeof(message)); };
|
||||||
|
|
||||||
|
if (!this->calculator.ExpMod(message, signature, SignatureSize, work_buf, work_buf_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return impl.Verify(message, sizeof(message), static_cast<const u8 *>(hash), hash_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Verify(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *msg, size_t msg_size) {
|
static bool Verify(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *msg, size_t msg_size) {
|
||||||
@@ -104,6 +151,22 @@ namespace ams::crypto {
|
|||||||
verifier.Update(msg, msg_size);
|
verifier.Update(msg, msg_size);
|
||||||
return verifier.Verify(sig, sig_size, work_buf, work_buf_size);
|
return verifier.Verify(sig, sig_size, work_buf, work_buf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool VerifyWithHash(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *hash, size_t hash_size) {
|
||||||
|
RsaPssVerifier<ModulusSize, Hash> verifier;
|
||||||
|
if (!verifier.Initialize(mod, mod_size, exp, exp_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return verifier.VerifyWithHash(sig, sig_size, hash, hash_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool VerifyWithHash(const void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *exp, size_t exp_size, const void *hash, size_t hash_size, void *work_buf, size_t work_buf_size) {
|
||||||
|
RsaPssVerifier<ModulusSize, Hash> verifier;
|
||||||
|
if (!verifier.Initialize(mod, mod_size, exp, exp_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return verifier.VerifyWithHash(sig, sig_size, hash, hash_size, work_buf, work_buf_size);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user