Compare commits
56 Commits
22_support
...
3ace80cc7b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ace80cc7b | ||
|
|
10722de8b9 | ||
|
|
59846adcb7 | ||
|
|
94e62a7b1b | ||
|
|
fbeea26919 | ||
|
|
38251801df | ||
|
|
7b6ee4916e | ||
|
|
556e628478 | ||
|
|
5388824be1 | ||
|
|
974a1025b8 | ||
|
|
9d21cfca4c | ||
|
|
1478f3443e | ||
|
|
f527e7fc48 | ||
|
|
7dccf3bffa | ||
|
|
4ea042510b | ||
|
|
d97f520058 | ||
|
|
3a3a2ca99b | ||
|
|
fcd46b4419 | ||
|
|
c046eeacdd | ||
|
|
4181169f80 | ||
|
|
47cfe05bb0 | ||
|
|
c497ffda75 | ||
|
|
15c434f185 | ||
|
|
7d38bf16cd | ||
|
|
2c7e2bfaae | ||
|
|
e655fd4b01 | ||
|
|
022000f668 | ||
|
|
d04c20a049 | ||
|
|
252f8685b4 | ||
|
|
020ed307b1 | ||
|
|
d9e1d799ab | ||
|
|
80bd459516 | ||
|
|
931e3c37fd | ||
|
|
4b4db91341 | ||
|
|
e3fc339fe5 | ||
|
|
a051c3c723 | ||
|
|
9a1ea02c8c | ||
|
|
bae1ad22ec | ||
|
|
cd1503a9ca | ||
|
|
72e3b0dd34 | ||
|
|
ac120cf84b | ||
|
|
97ffad2ab6 | ||
|
|
c8d68a3a8a | ||
|
|
8987d642d1 | ||
|
|
7ffb1da2ac | ||
|
|
5c426bf90d | ||
|
|
31ca20f3b7 | ||
|
|
174da786e4 | ||
|
|
4a8f7628c2 | ||
|
|
9d16ee6a74 | ||
|
|
3b9ee08c69 | ||
|
|
2694f31eb3 | ||
|
|
f3f1fa46ed | ||
|
|
5dd9816e3c | ||
|
|
5a5d9b206b | ||
|
|
f8a5a6c015 |
4
Makefile
4
Makefile
@@ -13,6 +13,10 @@ $(strip $1):
|
|||||||
@echo "Building $(strip $1)"
|
@echo "Building $(strip $1)"
|
||||||
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
|
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
|
||||||
|
|
||||||
|
dist-no-debug-$(strip $1):
|
||||||
|
@echo "Building $(strip $1)"
|
||||||
|
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk dist-no-debug ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
|
||||||
|
|
||||||
clean-$(strip $1):
|
clean-$(strip $1):
|
||||||
@echo "Cleaning $(strip $1)"
|
@echo "Cleaning $(strip $1)"
|
||||||
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
|
@$$(MAKE) -f $(CURRENT_DIRECTORY)/atmosphere.mk clean ATMOSPHERE_MAKEFILE_TARGET="$(strip $1)" ATMOSPHERE_BUILD_NAME="$(strip $2)" ATMOSPHERE_BOARD="$(strip $3)" ATMOSPHERE_CPU="$(strip $4)" $(strip $5)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ dist: dist-no-debug
|
|||||||
cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
|
cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
|
||||||
cp $(CURRENT_DIRECTORY)/troposphere/haze/haze.elf $(DIST_DIR)/haze.elf
|
cp $(CURRENT_DIRECTORY)/troposphere/haze/haze.elf $(DIST_DIR)/haze.elf
|
||||||
cp $(CURRENT_DIRECTORY)/troposphere/reboot_to_payload/reboot_to_payload.elf $(DIST_DIR)/reboot_to_payload.elf
|
cp $(CURRENT_DIRECTORY)/troposphere/reboot_to_payload/reboot_to_payload.elf $(DIST_DIR)/reboot_to_payload.elf
|
||||||
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
|
cd $(DIST_DIR); zip -1 -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
|
||||||
rm -rf $(DIST_DIR)
|
rm -rf $(DIST_DIR)
|
||||||
|
|
||||||
dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
|
dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
|
||||||
|
|||||||
@@ -15,6 +15,13 @@
|
|||||||
# Desc: Controls whether userland has access to the PMU registers.
|
# Desc: Controls whether userland has access to the PMU registers.
|
||||||
# NOTE: It is unknown what effects this has on official code.
|
# NOTE: It is unknown what effects this has on official code.
|
||||||
|
|
||||||
|
# Key: enable_mem_mode, default: 0.
|
||||||
|
# Desc: Controls whether boot config memory mode is taken into account
|
||||||
|
# for retail units. This does not affect development units.
|
||||||
|
# NOTE: On retail units max ram size is capped to 4GB.
|
||||||
|
# Enabling this will use the boot config memory mode parameter,
|
||||||
|
# which by default is auto and size gets set based on physical size.
|
||||||
|
|
||||||
# Key: blank_prodinfo_sysmmc, default: 0.
|
# Key: blank_prodinfo_sysmmc, default: 0.
|
||||||
# Desc: Controls whether PRODINFO should be blanked in sysmmc.
|
# Desc: Controls whether PRODINFO should be blanked in sysmmc.
|
||||||
# This will cause the system to see dummied out keys and
|
# This will cause the system to see dummied out keys and
|
||||||
@@ -51,6 +58,7 @@ debugmode=1
|
|||||||
debugmode_user=0
|
debugmode_user=0
|
||||||
disable_user_exception_handlers=0
|
disable_user_exception_handlers=0
|
||||||
enable_user_pmu_access=0
|
enable_user_pmu_access=0
|
||||||
|
enable_mem_mode=0
|
||||||
blank_prodinfo_sysmmc=0
|
blank_prodinfo_sysmmc=0
|
||||||
blank_prodinfo_emummc=0
|
blank_prodinfo_emummc=0
|
||||||
allow_writing_to_cal_sysmmc=0
|
allow_writing_to_cal_sysmmc=0
|
||||||
|
|||||||
@@ -1,4 +1,29 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
## 1.11.2
|
||||||
|
+ Basic support was added for 22.5.0.
|
||||||
|
+ Atmosphère was updated to use GCC 16/newlib (latest devkitA64/devkitARM releases).
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.11.1
|
||||||
|
+ Basic support was added for 22.1.0.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.11.0
|
||||||
|
+ Support was added for 22.0.0.
|
||||||
|
+ Special thanks to @alula for handling a large chunk of the necessary kernel, loader and erpt changes.
|
||||||
|
+ The console should boot and atmosphère should be fully functional.
|
||||||
|
+ **Please note**: A change in how applications/applets' lifespan is managed broke the homebrew ecosystem.
|
||||||
|
+ All applications and applets are expected to perform a clean exit by calling the relevant IPC commands.
|
||||||
|
+ Homebrew compiled with libnx and hbmenu itself explicitly avoid exiting so it can keep using the same process.
|
||||||
|
+ Properly fixing this would require a re-design of how homebrew is launched and terminated.
|
||||||
|
+ As a temporary solution, patches to the `am` sysmodule are now included which allow restoring the previous behavior and regain homebrew compatibility without any further changes.
|
||||||
|
+ Nonetheless, please report any issues you may face when testing homebrew to ensure no edge cases have been missed.
|
||||||
|
+ `exosphère` was updated to reflect the latest official secure monitor behavior.
|
||||||
|
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||||
|
+ `loader` was updated to reflect the latest official behavior.
|
||||||
|
+ `erpt` was updated to reflect the latest official behavior.
|
||||||
|
+ `pgl` was updated to fix a few issues.
|
||||||
|
+ Support was added for memory modes above 4GB (thanks @CTCaer).
|
||||||
|
+ A build time option to configure Joy-Con rails as UART for debugging was added (thanks @alula).
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
## 1.10.2
|
## 1.10.2
|
||||||
+ Basic support was added for 21.2.0.
|
+ Basic support was added for 21.2.0.
|
||||||
+ General system stability improvements to enhance the user's experience.
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
|||||||
6
emummc/.gitrepo
vendored
6
emummc/.gitrepo
vendored
@@ -6,7 +6,7 @@
|
|||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/m4xw/emummc
|
remote = https://github.com/m4xw/emummc
|
||||||
branch = develop
|
branch = develop
|
||||||
commit = 8ab963b0b1c24b68de8e0c98c62c7822a9765bf3
|
commit = f6b3a28ecea9834f96151a526de66abd11033b70
|
||||||
parent = 1e88f37892555da4c38ca6c95f43c56cc6bb87e6
|
parent = 1478f3443e8f04534edac8c15bf2d504663d0384
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.4.1
|
cmdver = 0.4.9
|
||||||
|
|||||||
2
emummc/README.md
vendored
2
emummc/README.md
vendored
@@ -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 - 21.2.0**
|
**1.0.0 - 22.5.0**
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Arbitrary SDMMC backend selection
|
* Arbitrary SDMMC backend selection
|
||||||
|
|||||||
8
emummc/source/FS/FS_offsets.c
vendored
8
emummc/source/FS/FS_offsets.c
vendored
@@ -85,6 +85,8 @@
|
|||||||
#include "offsets/2120_exfat.h"
|
#include "offsets/2120_exfat.h"
|
||||||
#include "offsets/2200.h"
|
#include "offsets/2200.h"
|
||||||
#include "offsets/2200_exfat.h"
|
#include "offsets/2200_exfat.h"
|
||||||
|
#include "offsets/2250.h"
|
||||||
|
#include "offsets/2250_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
|
||||||
@@ -181,6 +183,8 @@ DEFINE_OFFSET_STRUCT(_2120);
|
|||||||
DEFINE_OFFSET_STRUCT(_2120_EXFAT);
|
DEFINE_OFFSET_STRUCT(_2120_EXFAT);
|
||||||
DEFINE_OFFSET_STRUCT(_2200);
|
DEFINE_OFFSET_STRUCT(_2200);
|
||||||
DEFINE_OFFSET_STRUCT(_2200_EXFAT);
|
DEFINE_OFFSET_STRUCT(_2200_EXFAT);
|
||||||
|
DEFINE_OFFSET_STRUCT(_2250);
|
||||||
|
DEFINE_OFFSET_STRUCT(_2250_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) {
|
||||||
@@ -322,6 +326,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
|||||||
return &(GET_OFFSET_STRUCT_NAME(_2200));
|
return &(GET_OFFSET_STRUCT_NAME(_2200));
|
||||||
case FS_VER_22_0_0_EXFAT:
|
case FS_VER_22_0_0_EXFAT:
|
||||||
return &(GET_OFFSET_STRUCT_NAME(_2200_EXFAT));
|
return &(GET_OFFSET_STRUCT_NAME(_2200_EXFAT));
|
||||||
|
case FS_VER_22_5_0:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_2250));
|
||||||
|
case FS_VER_22_5_0_EXFAT:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_2250_EXFAT));
|
||||||
default:
|
default:
|
||||||
fatal_abort(Fatal_UnknownVersion);
|
fatal_abort(Fatal_UnknownVersion);
|
||||||
}
|
}
|
||||||
|
|||||||
3
emummc/source/FS/FS_versions.h
vendored
3
emummc/source/FS/FS_versions.h
vendored
@@ -124,6 +124,9 @@ enum FS_VER
|
|||||||
|
|
||||||
FS_VER_22_0_0,
|
FS_VER_22_0_0,
|
||||||
FS_VER_22_0_0_EXFAT,
|
FS_VER_22_0_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_22_5_0,
|
||||||
|
FS_VER_22_5_0_EXFAT,
|
||||||
|
|
||||||
FS_VER_MAX,
|
FS_VER_MAX,
|
||||||
};
|
};
|
||||||
|
|||||||
2
emummc/source/FS/offsets/2200.h
vendored
2
emummc/source/FS/offsets/2200.h
vendored
@@ -31,7 +31,7 @@
|
|||||||
#define FS_OFFSET_2200_CLKRST_SET_MIN_V_CLK_RATE 0x1CF260
|
#define FS_OFFSET_2200_CLKRST_SET_MIN_V_CLK_RATE 0x1CF260
|
||||||
|
|
||||||
// Misc funcs
|
// Misc funcs
|
||||||
#define FS_OFFSET_2200_LOCK_MUTEX 0x1CF260
|
#define FS_OFFSET_2200_LOCK_MUTEX 0x1A4EF0
|
||||||
#define FS_OFFSET_2200_UNLOCK_MUTEX 0x1A4F40
|
#define FS_OFFSET_2200_UNLOCK_MUTEX 0x1A4F40
|
||||||
|
|
||||||
#define FS_OFFSET_2200_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AC0B0
|
#define FS_OFFSET_2200_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AC0B0
|
||||||
|
|||||||
2
emummc/source/FS/offsets/2200_exfat.h
vendored
2
emummc/source/FS/offsets/2200_exfat.h
vendored
@@ -31,7 +31,7 @@
|
|||||||
#define FS_OFFSET_2200_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1DA450
|
#define FS_OFFSET_2200_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1DA450
|
||||||
|
|
||||||
// Misc funcs
|
// Misc funcs
|
||||||
#define FS_OFFSET_2200_EXFAT_LOCK_MUTEX 0x1DA450
|
#define FS_OFFSET_2200_EXFAT_LOCK_MUTEX 0x1B00E0
|
||||||
#define FS_OFFSET_2200_EXFAT_UNLOCK_MUTEX 0x1B0130
|
#define FS_OFFSET_2200_EXFAT_UNLOCK_MUTEX 0x1B0130
|
||||||
|
|
||||||
#define FS_OFFSET_2200_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1B72A0
|
#define FS_OFFSET_2200_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1B72A0
|
||||||
|
|||||||
59
emummc/source/FS/offsets/2250.h
vendored
Normal file
59
emummc/source/FS/offsets/2250.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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_2250_H__
|
||||||
|
#define __FS_2250_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_2250_SDMMC_ACCESSOR_GC 0x1B01C0
|
||||||
|
#define FS_OFFSET_2250_SDMMC_ACCESSOR_SD 0x1B21C0
|
||||||
|
#define FS_OFFSET_2250_SDMMC_ACCESSOR_NAND 0x1B07F0
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_2250_SDMMC_WRAPPER_READ 0x1AC0F0
|
||||||
|
#define FS_OFFSET_2250_SDMMC_WRAPPER_WRITE 0x1AC150
|
||||||
|
#define FS_OFFSET_2250_RTLD 0x2DED0
|
||||||
|
#define FS_OFFSET_2250_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_2250_CLKRST_SET_MIN_V_CLK_RATE 0x1CF260
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_2250_LOCK_MUTEX 0x1A4EF0
|
||||||
|
#define FS_OFFSET_2250_UNLOCK_MUTEX 0x1A4F40
|
||||||
|
|
||||||
|
#define FS_OFFSET_2250_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1AC0B0
|
||||||
|
#define FS_OFFSET_2250_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1AC0D0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_2250_SD_MUTEX 0xFF1408
|
||||||
|
#define FS_OFFSET_2250_NAND_MUTEX 0xFECD00
|
||||||
|
#define FS_OFFSET_2250_ACTIVE_PARTITION 0xFECD40
|
||||||
|
#define FS_OFFSET_2250_SDMMC_DAS_HANDLE 0xFCEB98
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_2250_SD_DAS_INIT 0x2B438
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_2250_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x000715EC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00082E64, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008B888, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x000A1B1C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_2250_H__
|
||||||
59
emummc/source/FS/offsets/2250_exfat.h
vendored
Normal file
59
emummc/source/FS/offsets/2250_exfat.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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_2250_EXFAT_H__
|
||||||
|
#define __FS_2250_EXFAT_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_2250_EXFAT_SDMMC_ACCESSOR_GC 0x1BB3B0
|
||||||
|
#define FS_OFFSET_2250_EXFAT_SDMMC_ACCESSOR_SD 0x1BD3B0
|
||||||
|
#define FS_OFFSET_2250_EXFAT_SDMMC_ACCESSOR_NAND 0x1BB9E0
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_READ 0x1B72E0
|
||||||
|
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_WRITE 0x1B7340
|
||||||
|
#define FS_OFFSET_2250_EXFAT_RTLD 0x2DED0
|
||||||
|
#define FS_OFFSET_2250_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x4C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_2250_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1DA450
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_2250_EXFAT_LOCK_MUTEX 0x1B00E0
|
||||||
|
#define FS_OFFSET_2250_EXFAT_UNLOCK_MUTEX 0x1B0130
|
||||||
|
|
||||||
|
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1B72A0
|
||||||
|
#define FS_OFFSET_2250_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1B72C0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_2250_EXFAT_SD_MUTEX 0x1002408
|
||||||
|
#define FS_OFFSET_2250_EXFAT_NAND_MUTEX 0xFFDD00
|
||||||
|
#define FS_OFFSET_2250_EXFAT_ACTIVE_PARTITION 0xFFDD40
|
||||||
|
#define FS_OFFSET_2250_EXFAT_SDMMC_DAS_HANDLE 0xFDBB98
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_2250_EXFAT_SD_DAS_INIT 0x2B438
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_2250_EXFAT_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x000715EC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00082E64, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008B888, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x000A1B1C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_2250_EXFAT_H__
|
||||||
@@ -132,10 +132,13 @@ namespace ams::secmon::smc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 GetMemoryMode() {
|
u32 GetMemoryMode() {
|
||||||
/* Unless development function is enabled, we're 4 GB. */
|
/* Unless development function or forced boot config memory size is enabled, we're 4 GB. */
|
||||||
u32 memory_mode = pkg1::MemoryMode_4GB;
|
u32 memory_mode = pkg1::MemoryMode_4GB;
|
||||||
|
|
||||||
if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) {
|
const auto &bcd = GetBootConfig().data;
|
||||||
|
const auto &sc = GetSecmonConfiguration(); /* Exosphere extensions */
|
||||||
|
|
||||||
|
if (bcd.IsDevelopmentFunctionEnabled() || sc.IsBootConfigMemoryModeEnabled()) {
|
||||||
memory_mode = GetMemoryMode(bcd.GetMemoryMode());
|
memory_mode = GetMemoryMode(bcd.GetMemoryMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,17 +149,19 @@ namespace ams::secmon::smc {
|
|||||||
pkg1::MemorySize memory_size = pkg1::MemorySize_4GB;
|
pkg1::MemorySize memory_size = pkg1::MemorySize_4GB;
|
||||||
util::BitPack32 value = {};
|
util::BitPack32 value = {};
|
||||||
|
|
||||||
if (const auto &bcd = GetBootConfig().data; bcd.IsDevelopmentFunctionEnabled()) {
|
const auto &bcd = GetBootConfig().data;
|
||||||
memory_size = GetMemorySize(GetMemoryMode(bcd.GetMemoryMode()));
|
const auto &sc = GetSecmonConfiguration(); /* Exosphere extensions */
|
||||||
|
|
||||||
|
if (bcd.IsDevelopmentFunctionEnabled()) {
|
||||||
value.Set<KernelConfiguration::Flags1>(bcd.GetKernelFlags1());
|
value.Set<KernelConfiguration::Flags1>(bcd.GetKernelFlags1());
|
||||||
value.Set<KernelConfiguration::Flags0>(bcd.GetKernelFlags0());
|
value.Set<KernelConfiguration::Flags0>(bcd.GetKernelFlags0());
|
||||||
}
|
}
|
||||||
|
|
||||||
value.Set<KernelConfiguration::PhysicalMemorySize>(memory_size);
|
if (bcd.IsDevelopmentFunctionEnabled() || sc.IsBootConfigMemoryModeEnabled()) {
|
||||||
|
memory_size = GetMemorySize(GetMemoryMode(bcd.GetMemoryMode()));
|
||||||
|
}
|
||||||
|
|
||||||
/* Exosphere extensions. */
|
value.Set<KernelConfiguration::PhysicalMemorySize>(memory_size);
|
||||||
const auto &sc = GetSecmonConfiguration();
|
|
||||||
|
|
||||||
if (!sc.DisableUserModeExceptionHandlers()) {
|
if (!sc.DisableUserModeExceptionHandlers()) {
|
||||||
value.Set<KernelConfiguration::EnableUserExceptionHandlers>(true);
|
value.Set<KernelConfiguration::EnableUserExceptionHandlers>(true);
|
||||||
@@ -169,6 +174,27 @@ namespace ams::secmon::smc {
|
|||||||
return value.value;
|
return value.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fuse::DramId GetDramIdAdjusted() {
|
||||||
|
const auto dram_id = fuse::GetDramId();
|
||||||
|
AMS_ABORT_UNLESS(dram_id < fuse::DramId_Count);
|
||||||
|
|
||||||
|
const auto fuse_mem_size = DramIdToMemorySize[dram_id];
|
||||||
|
const auto phys_mem_size = GetPhysicalMemorySize();
|
||||||
|
|
||||||
|
AMS_ABORT_UNLESS(fuse_mem_size <= phys_mem_size);
|
||||||
|
|
||||||
|
if (fuse_mem_size == phys_mem_size) {
|
||||||
|
return dram_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust Dram ID to match density/ranks. */
|
||||||
|
if (GetSocType() == fuse::SocType_Erista) {
|
||||||
|
return fuse::DramId_IcosaSamsung6GB;
|
||||||
|
} else { /* fuse::SocType_Mariko */
|
||||||
|
return fuse::DramId_IowaSamsung1y8GBX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constinit u64 g_payload_address = 0;
|
constinit u64 g_payload_address = 0;
|
||||||
constinit bool g_set_true_target_firmware = false;
|
constinit bool g_set_true_target_firmware = false;
|
||||||
|
|
||||||
@@ -178,7 +204,7 @@ namespace ams::secmon::smc {
|
|||||||
args.r[1] = GetBootConfig().signed_data.IsProgramVerificationDisabled();
|
args.r[1] = GetBootConfig().signed_data.IsProgramVerificationDisabled();
|
||||||
break;
|
break;
|
||||||
case ConfigItem::DramId:
|
case ConfigItem::DramId:
|
||||||
args.r[1] = fuse::GetDramId();
|
args.r[1] = GetDramIdAdjusted(); /* Nintendo: fuse::GetDramId() */
|
||||||
break;
|
break;
|
||||||
case ConfigItem::SecurityEngineInterruptNumber:
|
case ConfigItem::SecurityEngineInterruptNumber:
|
||||||
args.r[1] = SecurityEngineUserInterruptId;
|
args.r[1] = SecurityEngineUserInterruptId;
|
||||||
@@ -471,9 +497,18 @@ namespace ams::secmon::smc {
|
|||||||
|
|
||||||
/* For exosphere's usage. */
|
/* For exosphere's usage. */
|
||||||
pkg1::MemorySize GetPhysicalMemorySize() {
|
pkg1::MemorySize GetPhysicalMemorySize() {
|
||||||
const auto dram_id = fuse::GetDramId();
|
const uintptr_t MC = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress();
|
||||||
AMS_ABORT_UNLESS(dram_id < fuse::DramId_Count);
|
const u32 mem_size = reg::Read(MC + MC_EMEM_CFG) & 0x3FFF;
|
||||||
return DramIdToMemorySize[dram_id];
|
|
||||||
|
switch (mem_size >> 10) {
|
||||||
|
case 4:
|
||||||
|
default:
|
||||||
|
return pkg1::MemorySize_4GB;
|
||||||
|
case 6:
|
||||||
|
return pkg1::MemorySize_6GB;
|
||||||
|
case 8:
|
||||||
|
return pkg1::MemorySize_8GB;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -545,6 +545,12 @@ namespace ams::nxboot {
|
|||||||
} else {
|
} else {
|
||||||
storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess;
|
storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess;
|
||||||
}
|
}
|
||||||
|
} else if (std::strcmp(entry.key, "enable_mem_mode") == 0) {
|
||||||
|
if (entry.value[0] == '1') {
|
||||||
|
storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_BootConfigMemoryModeEnabled;
|
||||||
|
} else {
|
||||||
|
storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_BootConfigMemoryModeEnabled;
|
||||||
|
}
|
||||||
} else if (std::strcmp(entry.key, "blank_prodinfo_sysmmc") == 0) {
|
} else if (std::strcmp(entry.key, "blank_prodinfo_sysmmc") == 0) {
|
||||||
if (!emummc_enabled) {
|
if (!emummc_enabled) {
|
||||||
if (entry.value[0] == '1') {
|
if (entry.value[0] == '1') {
|
||||||
|
|||||||
@@ -194,6 +194,9 @@ namespace ams::nxboot {
|
|||||||
|
|
||||||
FsVersion_22_0_0,
|
FsVersion_22_0_0,
|
||||||
FsVersion_22_0_0_Exfat,
|
FsVersion_22_0_0_Exfat,
|
||||||
|
|
||||||
|
FsVersion_22_5_0,
|
||||||
|
FsVersion_22_5_0_Exfat,
|
||||||
|
|
||||||
FsVersion_Count,
|
FsVersion_Count,
|
||||||
};
|
};
|
||||||
@@ -302,6 +305,9 @@ namespace ams::nxboot {
|
|||||||
|
|
||||||
{ 0xB7, 0xA2, 0x97, 0x39, 0xB7, 0xED, 0xDE, 0xFC }, /* FsVersion_22_0_0 */
|
{ 0xB7, 0xA2, 0x97, 0x39, 0xB7, 0xED, 0xDE, 0xFC }, /* FsVersion_22_0_0 */
|
||||||
{ 0xFB, 0x0B, 0x68, 0xDB, 0x24, 0x03, 0xD1, 0x19 }, /* FsVersion_22_0_0_Exfat */
|
{ 0xFB, 0x0B, 0x68, 0xDB, 0x24, 0x03, 0xD1, 0x19 }, /* FsVersion_22_0_0_Exfat */
|
||||||
|
|
||||||
|
{ 0x53, 0x6D, 0x93, 0x84, 0x69, 0xFE, 0x73, 0xBE }, /* FsVersion_22_5_0 */
|
||||||
|
{ 0xD4, 0x45, 0x28, 0x29, 0x5B, 0x41, 0x92, 0xBA }, /* FsVersion_22_5_0_Exfat */
|
||||||
};
|
};
|
||||||
|
|
||||||
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
|
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
|
||||||
@@ -716,11 +722,13 @@ namespace ams::nxboot {
|
|||||||
AddPatch(fs_meta, 0x18AD40, NogcPatch1, sizeof(NogcPatch1));
|
AddPatch(fs_meta, 0x18AD40, NogcPatch1, sizeof(NogcPatch1));
|
||||||
break;
|
break;
|
||||||
case FsVersion_22_0_0:
|
case FsVersion_22_0_0:
|
||||||
|
case FsVersion_22_5_0:
|
||||||
AddPatch(fs_meta, 0x1B023D, NogcPatch0, sizeof(NogcPatch0));
|
AddPatch(fs_meta, 0x1B023D, NogcPatch0, sizeof(NogcPatch0));
|
||||||
AddPatch(fs_meta, 0x1B0255, NogcPatch0, sizeof(NogcPatch0));
|
AddPatch(fs_meta, 0x1B0255, NogcPatch0, sizeof(NogcPatch0));
|
||||||
AddPatch(fs_meta, 0x183060, NogcPatch1, sizeof(NogcPatch1));
|
AddPatch(fs_meta, 0x183060, NogcPatch1, sizeof(NogcPatch1));
|
||||||
break;
|
break;
|
||||||
case FsVersion_22_0_0_Exfat:
|
case FsVersion_22_0_0_Exfat:
|
||||||
|
case FsVersion_22_5_0_Exfat:
|
||||||
AddPatch(fs_meta, 0x1BB42D, NogcPatch0, sizeof(NogcPatch0));
|
AddPatch(fs_meta, 0x1BB42D, NogcPatch0, sizeof(NogcPatch0));
|
||||||
AddPatch(fs_meta, 0x1BB445, NogcPatch0, sizeof(NogcPatch0));
|
AddPatch(fs_meta, 0x1BB445, NogcPatch0, sizeof(NogcPatch0));
|
||||||
AddPatch(fs_meta, 0x18E250, NogcPatch1, sizeof(NogcPatch1));
|
AddPatch(fs_meta, 0x18E250, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
|||||||
@@ -1355,6 +1355,9 @@ namespace ams::nxboot {
|
|||||||
uint32_t emc_zcal_wait_cnt_new = dst_timing->burst_regs.emc_zcal_wait_cnt;
|
uint32_t emc_zcal_wait_cnt_new = dst_timing->burst_regs.emc_zcal_wait_cnt;
|
||||||
emc_zcal_wait_cnt_old &= ~0x7ff;
|
emc_zcal_wait_cnt_old &= ~0x7ff;
|
||||||
emc_zcal_wait_cnt_new &= ~0x7ff;
|
emc_zcal_wait_cnt_new &= ~0x7ff;
|
||||||
|
|
||||||
|
/* TODO: Unused variable. */
|
||||||
|
AMS_UNUSED(emc_zcal_wait_cnt_old);
|
||||||
|
|
||||||
if (dram_type == DRAM_TYPE_LPDDR4) {
|
if (dram_type == DRAM_TYPE_LPDDR4) {
|
||||||
zq_wait_long = std::max<u32>(1, util::DivideUp(1000000, destination_clock_period));
|
zq_wait_long = std::max<u32>(1, util::DivideUp(1000000, destination_clock_period));
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||||
branch = master
|
branch = master
|
||||||
commit = 9a8703e710760be8c88147d15414a1c581711625
|
commit = d3083af1827cd6ca2a96feb9316eb85cd01bae1f
|
||||||
parent = eb34f9789c62745d87f37e76761b14d946bac300
|
parent = 974a1025b834136134e8133d8db23f69cb5ae0be
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.4.1
|
cmdver = 0.4.9
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace ams::secmon {
|
|||||||
SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary = (1u << 5),
|
SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary = (1u << 5),
|
||||||
SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc = (1u << 6),
|
SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc = (1u << 6),
|
||||||
SecureMonitorConfigurationFlag_ForceEnableUsb30 = (1u << 7),
|
SecureMonitorConfigurationFlag_ForceEnableUsb30 = (1u << 7),
|
||||||
|
SecureMonitorConfigurationFlag_BootConfigMemoryModeEnabled = (1u << 8),
|
||||||
|
|
||||||
SecureMonitorConfigurationFlag_Default = SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel,
|
SecureMonitorConfigurationFlag_Default = SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel,
|
||||||
};
|
};
|
||||||
@@ -103,6 +104,7 @@ namespace ams::secmon {
|
|||||||
constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; }
|
constexpr bool ShouldUseBlankCalibrationBinary() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary) != 0; }
|
||||||
constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags[0] & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; }
|
constexpr bool AllowWritingToCalibrationBinarySysmmc() const { return (this->flags[0] & SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc) != 0; }
|
||||||
constexpr bool IsUsb30ForceEnabled() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ForceEnableUsb30) != 0; }
|
constexpr bool IsUsb30ForceEnabled() const { return (this->flags[0] & SecureMonitorConfigurationFlag_ForceEnableUsb30) != 0; }
|
||||||
|
constexpr bool IsBootConfigMemoryModeEnabled() const { return (this->flags[0] & SecureMonitorConfigurationFlag_BootConfigMemoryModeEnabled) != 0; }
|
||||||
|
|
||||||
constexpr bool IsDevelopmentFunctionEnabled(bool for_kern) const { return for_kern ? this->IsDevelopmentFunctionEnabledForKernel() : this->IsDevelopmentFunctionEnabledForUser(); }
|
constexpr bool IsDevelopmentFunctionEnabled(bool for_kern) const { return for_kern ? this->IsDevelopmentFunctionEnabledForKernel() : this->IsDevelopmentFunctionEnabledForUser(); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -104,7 +104,10 @@ namespace ams::se {
|
|||||||
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 0) : 0;
|
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 0) : 0;
|
||||||
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 1) : 0;
|
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 1) : 0;
|
||||||
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 2) : 0;
|
value |= ((flags & KeySlotLockFlags_KeyRead) == 0) ? (1u << 2) : 0;
|
||||||
|
|
||||||
|
/* TODO: Unused variable. */
|
||||||
|
AMS_UNUSED(value);
|
||||||
|
|
||||||
reg::Write(SE->SE_RSA_KEYTABLE_ACCESS[slot], SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYREAD, (flags & KeySlotLockFlags_KeyRead) != 0, DISABLE, ENABLE),
|
reg::Write(SE->SE_RSA_KEYTABLE_ACCESS[slot], SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYREAD, (flags & KeySlotLockFlags_KeyRead) != 0, DISABLE, ENABLE),
|
||||||
SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUPDATE, (flags & KeySlotLockFlags_KeyWrite) != 0, DISABLE, ENABLE),
|
SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUPDATE, (flags & KeySlotLockFlags_KeyWrite) != 0, DISABLE, ENABLE),
|
||||||
SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUSE, (flags & KeySlotLockFlags_KeyUse) != 0, DISABLE, ENABLE));
|
SE_REG_BITS_ENUM_SEL(RSA_KEYTABLE_ACCESS_KEYUSE, (flags & KeySlotLockFlags_KeyUse) != 0, DISABLE, ENABLE));
|
||||||
|
|||||||
@@ -729,6 +729,9 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
MESOSPHERE_ASSERT(mapped_pages == num_pages);
|
MESOSPHERE_ASSERT(mapped_pages == num_pages);
|
||||||
|
|
||||||
|
/* TODO: Unused variable. */
|
||||||
|
AMS_UNUSED(mapped_pages);
|
||||||
|
|
||||||
/* Perform what coalescing we can. */
|
/* Perform what coalescing we can. */
|
||||||
this->MergePages(orig_virt_addr, num_pages, page_list);
|
this->MergePages(orig_virt_addr, num_pages, page_list);
|
||||||
|
|||||||
@@ -682,7 +682,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory32BitEPvPKvm:
|
|||||||
mov x30, x10
|
mov x30, x10
|
||||||
|
|
||||||
/* Write the word to io. */
|
/* Write the word to io. */
|
||||||
sttr w9, [x5]
|
sttr w9, [x4]
|
||||||
dsb sy
|
dsb sy
|
||||||
|
|
||||||
2: /* Continue. */
|
2: /* Continue. */
|
||||||
@@ -727,7 +727,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl18WriteIoMemory16BitEPvPKvm:
|
|||||||
mov x30, x10
|
mov x30, x10
|
||||||
|
|
||||||
/* Write the word to io. */
|
/* Write the word to io. */
|
||||||
sttrh w9, [x5]
|
sttrh w9, [x4]
|
||||||
dsb sy
|
dsb sy
|
||||||
|
|
||||||
2: /* Continue. */
|
2: /* Continue. */
|
||||||
@@ -772,7 +772,7 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess4Impl17WriteIoMemory8BitEPvPKvm:
|
|||||||
mov x30, x10
|
mov x30, x10
|
||||||
|
|
||||||
/* Write the word to io. */
|
/* Write the word to io. */
|
||||||
sttrb w9, [x5]
|
sttrb w9, [x4]
|
||||||
dsb sy
|
dsb sy
|
||||||
|
|
||||||
2: /* Continue. */
|
2: /* Continue. */
|
||||||
|
|||||||
@@ -756,11 +756,13 @@ namespace ams::kern {
|
|||||||
case ams::svc::DebugException_UndefinedSystemCall:
|
case ams::svc::DebugException_UndefinedSystemCall:
|
||||||
{
|
{
|
||||||
MESOSPHERE_ASSERT(num_params >= 3);
|
MESOSPHERE_ASSERT(num_params >= 3);
|
||||||
|
|
||||||
info->info.exception.exception_address = params[1];
|
/* Keep the compiler happy, even though the assert has us covered. */
|
||||||
|
if (num_params >= 3) {
|
||||||
info->info.exception.exception_data_count = 1;
|
info->info.exception.exception_address = params[1];
|
||||||
info->info.exception.exception_data[0] = params[2];
|
info->info.exception.exception_data_count = 1;
|
||||||
|
info->info.exception.exception_data[0] = params[2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_DebuggerAttached:
|
case ams::svc::DebugException_DebuggerAttached:
|
||||||
@@ -773,9 +775,12 @@ namespace ams::kern {
|
|||||||
case ams::svc::DebugException_UserBreak:
|
case ams::svc::DebugException_UserBreak:
|
||||||
{
|
{
|
||||||
MESOSPHERE_ASSERT(num_params >= 2);
|
MESOSPHERE_ASSERT(num_params >= 2);
|
||||||
|
|
||||||
info->info.exception.exception_address = params[1];
|
/* Keep the compiler happy, even though the assert has us covered. */
|
||||||
|
if (num_params >= 2) {
|
||||||
|
info->info.exception.exception_address = params[1];
|
||||||
|
}
|
||||||
|
|
||||||
info->info.exception.exception_data_count = 0;
|
info->info.exception.exception_data_count = 0;
|
||||||
for (size_t i = 2; i < num_params; ++i) {
|
for (size_t i = 2; i < num_params; ++i) {
|
||||||
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
|
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
|
||||||
@@ -805,8 +810,11 @@ namespace ams::kern {
|
|||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
MESOSPHERE_ASSERT(num_params >= 2);
|
MESOSPHERE_ASSERT(num_params >= 2);
|
||||||
|
|
||||||
info->info.exception.exception_address = params[1];
|
/* Keep the compiler happy, even though the assert has us covered. */
|
||||||
|
if (num_params >= 2) {
|
||||||
|
info->info.exception.exception_address = params[1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -979,6 +979,7 @@
|
|||||||
HANDLER(FsSaveDataFileSystemPeakMountCount, 777, FsProxyErrorInfo3, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(FsSaveDataFileSystemPeakMountCount, 777, FsProxyErrorInfo3, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(TestBool, 778, Test, FieldType_Bool, FieldFlag_None ) \
|
HANDLER(TestBool, 778, Test, FieldType_Bool, FieldFlag_None ) \
|
||||||
HANDLER(TestI8Array, 779, Test, FieldType_I8Array, FieldFlag_None ) \
|
HANDLER(TestI8Array, 779, Test, FieldType_I8Array, FieldFlag_None ) \
|
||||||
|
HANDLER(SslProcessHeapAllocatable, 781, NetworkSecurityCertificateInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(TestStringNx, 1000, TestNx, FieldType_String, FieldFlag_None ) \
|
HANDLER(TestStringNx, 1000, TestNx, FieldType_String, FieldFlag_None ) \
|
||||||
HANDLER(BoostModeCurrentLimit, 1001, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(BoostModeCurrentLimit, 1001, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(ChargeConfiguration, 1002, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(ChargeConfiguration, 1002, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ namespace ams::erpt {
|
|||||||
|
|
||||||
struct CreateReportOptionFlag {
|
struct CreateReportOptionFlag {
|
||||||
using SubmitFsInfo = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>::Flag<0>;
|
using SubmitFsInfo = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>::Flag<0>;
|
||||||
|
using Unknown0x20000 = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>::Flag<17>; /* TODO: What is this, it's checked in Reporter::CreateReport or below */
|
||||||
};
|
};
|
||||||
|
|
||||||
using CreateReportOptionFlagSet = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>;
|
using CreateReportOptionFlagSet = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>;
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ namespace ams::fs {
|
|||||||
|
|
||||||
struct GameCardErrorReportInfo {
|
struct GameCardErrorReportInfo {
|
||||||
u16 game_card_crc_error_num;
|
u16 game_card_crc_error_num;
|
||||||
u16 reserved1;
|
u8 last_deactivate_reason;
|
||||||
|
u8 reserved1;
|
||||||
u16 asic_crc_error_num;
|
u16 asic_crc_error_num;
|
||||||
u16 reserved2;
|
u16 reserved2;
|
||||||
u16 refresh_num;
|
u16 refresh_num;
|
||||||
@@ -73,7 +74,8 @@ namespace ams::fs {
|
|||||||
u32 awaken_count;
|
u32 awaken_count;
|
||||||
u32 read_count_from_insert;
|
u32 read_count_from_insert;
|
||||||
u32 read_count_from_awaken;
|
u32 read_count_from_awaken;
|
||||||
u8 reserved5[8];
|
u32 last_deactivate_reason_result;
|
||||||
|
u32 reserved5;
|
||||||
};
|
};
|
||||||
static_assert(util::is_pod<GameCardErrorReportInfo>::value);
|
static_assert(util::is_pod<GameCardErrorReportInfo>::value);
|
||||||
static_assert(sizeof(GameCardErrorReportInfo) == 0x40);
|
static_assert(sizeof(GameCardErrorReportInfo) == 0x40);
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ namespace ams::hos {
|
|||||||
Version_21_1_0 = ::ams::TargetFirmware_21_1_0,
|
Version_21_1_0 = ::ams::TargetFirmware_21_1_0,
|
||||||
Version_21_2_0 = ::ams::TargetFirmware_21_2_0,
|
Version_21_2_0 = ::ams::TargetFirmware_21_2_0,
|
||||||
Version_22_0_0 = ::ams::TargetFirmware_22_0_0,
|
Version_22_0_0 = ::ams::TargetFirmware_22_0_0,
|
||||||
|
Version_22_1_0 = ::ams::TargetFirmware_22_1_0,
|
||||||
|
Version_22_5_0 = ::ams::TargetFirmware_22_5_0,
|
||||||
|
|
||||||
Version_Current = ::ams::TargetFirmware_Current,
|
Version_Current = ::ams::TargetFirmware_Current,
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ namespace ams::pgl {
|
|||||||
u32 version;
|
u32 version;
|
||||||
ncm::ContentType content_type;
|
ncm::ContentType content_type;
|
||||||
u8 id_offset;
|
u8 id_offset;
|
||||||
u8 reserved_0E[2];
|
ncm::ContentMetaType content_meta_type;
|
||||||
|
u8 reserved_0F;
|
||||||
|
|
||||||
static constexpr ContentMetaInfo Make(u64 id, u32 version, ncm::ContentType content_type, u8 id_offset) {
|
static constexpr ContentMetaInfo Make(u64 id, u32 version, ncm::ContentType content_type, u8 id_offset) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -18,14 +18,18 @@
|
|||||||
#include <vapours.hpp>
|
#include <vapours.hpp>
|
||||||
|
|
||||||
namespace ams::util {
|
namespace ams::util {
|
||||||
|
|
||||||
|
constexpr size_t DecompressZstdWithBicWorkBufferSizeDefault = 0x176E8;
|
||||||
|
|
||||||
/* Compression utilities. */
|
/* Compression utilities. */
|
||||||
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size);
|
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||||
size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size);
|
size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||||
|
size_t CompressZstdWithBic(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||||
|
|
||||||
/* Decompression utilities. */
|
/* Decompression utilities. */
|
||||||
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size);
|
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||||
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size);
|
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||||
bool DecompressZstdForLoader(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size);
|
size_t DecompressZstdWithBic(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||||
|
bool DecompressZstdWithBic(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -19,5 +19,6 @@
|
|||||||
namespace ams::erpt::srv {
|
namespace ams::erpt::srv {
|
||||||
|
|
||||||
Result SubmitFsInfo();
|
Result SubmitFsInfo();
|
||||||
|
void ClearFsInfo();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -363,6 +363,8 @@ namespace ams::erpt::srv {
|
|||||||
R_ABORT_UNLESS(record->Add(FieldId_GameCardReadCountFromAwaken, ei.read_count_from_awaken));
|
R_ABORT_UNLESS(record->Add(FieldId_GameCardReadCountFromAwaken, ei.read_count_from_awaken));
|
||||||
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageAddress, ei.last_read_error_page_address));
|
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageAddress, ei.last_read_error_page_address));
|
||||||
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageCount, ei.last_read_error_page_count));
|
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastReadErrorPageCount, ei.last_read_error_page_count));
|
||||||
|
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastDeactivateReasonResult, ei.last_deactivate_reason_result));
|
||||||
|
R_ABORT_UNLESS(record->Add(FieldId_GameCardLastDeactivateReason, ei.last_deactivate_reason));
|
||||||
|
|
||||||
/* Submit the record. */
|
/* Submit the record. */
|
||||||
R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record)));
|
R_ABORT_UNLESS(Context::SubmitContextRecord(std::move(record)));
|
||||||
@@ -496,4 +498,27 @@ namespace ams::erpt::srv {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClearFsInfo() {
|
||||||
|
Context::ClearContext(CategoryId_NANDTypeInfo);
|
||||||
|
Context::ClearContext(CategoryId_NANDSpeedModeInfo);
|
||||||
|
Context::ClearContext(CategoryId_NANDExtendedCsd);
|
||||||
|
Context::ClearContext(CategoryId_NANDPatrolInfo);
|
||||||
|
Context::ClearContext(CategoryId_NANDErrorInfo);
|
||||||
|
Context::ClearContext(CategoryId_NANDDriverLog);
|
||||||
|
Context::ClearContext(CategoryId_MicroSDTypeInfo);
|
||||||
|
Context::ClearContext(CategoryId_MicroSDSpeedModeInfo);
|
||||||
|
Context::ClearContext(CategoryId_SdCardSizeSpec);
|
||||||
|
Context::ClearContext(CategoryId_SdCardActivationInfo);
|
||||||
|
Context::ClearContext(CategoryId_SdCardErrorInfo);
|
||||||
|
Context::ClearContext(CategoryId_SdCardDriverLog);
|
||||||
|
Context::ClearContext(CategoryId_GameCardCIDInfo);
|
||||||
|
Context::ClearContext(CategoryId_GameCardErrorInfo);
|
||||||
|
Context::ClearContext(CategoryId_GameCardDetailedErrorInfo);
|
||||||
|
Context::ClearContext(CategoryId_GameCardLogInfo);
|
||||||
|
Context::ClearContext(CategoryId_FsProxyErrorInfo);
|
||||||
|
Context::ClearContext(CategoryId_FsProxyErrorInfo2);
|
||||||
|
Context::ClearContext(CategoryId_FsProxyErrorInfo3);
|
||||||
|
Context::ClearContext(CategoryId_FsMemoryInfo);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -423,7 +423,11 @@ namespace ams::erpt::srv {
|
|||||||
|
|
||||||
auto report = std::make_unique<Report>(record.get(), redirect_new_reports);
|
auto report = std::make_unique<Report>(record.get(), redirect_new_reports);
|
||||||
R_UNLESS(report != nullptr, erpt::ResultOutOfMemory());
|
R_UNLESS(report != nullptr, erpt::ResultOutOfMemory());
|
||||||
auto report_guard = SCOPE_GUARD { const auto delete_res = report->Delete(); R_ASSERT(delete_res); AMS_UNUSED(delete_res); };
|
auto report_guard = SCOPE_GUARD {
|
||||||
|
const auto delete_res = report->Delete();
|
||||||
|
R_ASSERT(delete_res);
|
||||||
|
AMS_UNUSED(delete_res);
|
||||||
|
};
|
||||||
|
|
||||||
R_TRY(Context::WriteContextsToReport(report.get()));
|
R_TRY(Context::WriteContextsToReport(report.get()));
|
||||||
R_TRY(report->GetSize(std::addressof(record->m_info.report_size)));
|
R_TRY(report->GetSize(std::addressof(record->m_info.report_size)));
|
||||||
@@ -434,7 +438,7 @@ namespace ams::erpt::srv {
|
|||||||
} else {
|
} else {
|
||||||
/* If we are redirecting new reports, we don't want to store the report in the journal. */
|
/* If we are redirecting new reports, we don't want to store the report in the journal. */
|
||||||
/* We should take this opportunity to delete any attachments associated with the report. */
|
/* We should take this opportunity to delete any attachments associated with the report. */
|
||||||
R_ABORT_UNLESS(JournalForAttachments::DeleteAttachments(report_id));
|
R_TRY(JournalForAttachments::DeleteAttachments(report_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
R_TRY(Journal::Commit());
|
R_TRY(Journal::Commit());
|
||||||
@@ -489,6 +493,20 @@ namespace ams::erpt::srv {
|
|||||||
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfo));
|
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfo));
|
||||||
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoAuto));
|
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoAuto));
|
||||||
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoDefaults));
|
static_cast<void>(Context::ClearContext(CategoryId_ErrorInfoDefaults));
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||||
|
/* TODO: What else is missing? */
|
||||||
|
if (hos::GetVersion() >= hos::Version_17_0_0 && flags.Test<CreateReportOptionFlag::SubmitFsInfo>()) {
|
||||||
|
ClearFsInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if (erpt::ResultInvalidPowerState::Includes(...)) {
|
||||||
|
* Nintendo ignores this and sends "power_state_violation" play report if this error happens.
|
||||||
|
* } else {
|
||||||
|
* Nintendo sends "write_failure" play report if any other error happens.
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Get the context entry pointer. */
|
/* Get the context entry pointer. */
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace ams::hos {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
exosphere::ApiInfo GetExosphereApiInfo(bool allow_approximate) {
|
exosphere::ApiInfo GetExosphereApiInfo(bool allow_approximate) {
|
||||||
exosphere::ApiInfo info;
|
exosphere::ApiInfo info = exosphere::ApiInfo{ util::BitPack64{0} };
|
||||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||||
while (true) {
|
while (true) {
|
||||||
if (R_SUCCEEDED(GetExosphereApiInfo(std::addressof(info)))) {
|
if (R_SUCCEEDED(GetExosphereApiInfo(std::addressof(info)))) {
|
||||||
|
|||||||
@@ -220,6 +220,9 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
/* Assert that we copied the right number of infos. */
|
/* Assert that we copied the right number of infos. */
|
||||||
AMS_ASSERT(count == fragment_count);
|
AMS_ASSERT(count == fragment_count);
|
||||||
|
|
||||||
|
/* TODO: Unused variable. */
|
||||||
|
AMS_UNUSED(count);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -432,6 +435,9 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
/* Assert that we copied the right number of infos. */
|
/* Assert that we copied the right number of infos. */
|
||||||
AMS_ASSERT(count == fragment_count);
|
AMS_ASSERT(count == fragment_count);
|
||||||
|
|
||||||
|
/* TODO: Unused variable. */
|
||||||
|
AMS_UNUSED(count);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,15 +75,15 @@ namespace ams::pgl::srv {
|
|||||||
NON_COPYABLE(HostPackageReader);
|
NON_COPYABLE(HostPackageReader);
|
||||||
NON_MOVEABLE(HostPackageReader);
|
NON_MOVEABLE(HostPackageReader);
|
||||||
private:
|
private:
|
||||||
char m_content_path[fs::EntryNameLengthMax] = {};
|
char m_content_path[fs::EntryNameLengthMax] = {};
|
||||||
ExtensionType m_extension_type = ExtensionType::None;
|
ExtensionType m_extension_type = ExtensionType::None;
|
||||||
char m_mount_name[fs::MountNameLengthMax] = {};
|
char m_mount_name[fs::MountNameLengthMax + 1] = {};
|
||||||
bool m_is_mounted = false;
|
bool m_is_mounted = false;
|
||||||
ncm::AutoBuffer m_content_meta_buffer;
|
ncm::AutoBuffer m_content_meta_buffer;
|
||||||
ncm::ProgramId m_program_id = ncm::InvalidProgramId;
|
ncm::ProgramId m_program_id = ncm::InvalidProgramId;
|
||||||
u32 m_program_version = 0;
|
u32 m_program_version = 0;
|
||||||
ncm::ContentMetaType m_content_meta_type = static_cast<ncm::ContentMetaType>(0);
|
ncm::ContentMetaType m_content_meta_type = static_cast<ncm::ContentMetaType>(0);
|
||||||
u8 m_program_index = 0;
|
u8 m_program_index = 0;
|
||||||
public:
|
public:
|
||||||
HostPackageReader() : m_content_meta_buffer() { /* ... */ }
|
HostPackageReader() : m_content_meta_buffer() { /* ... */ }
|
||||||
~HostPackageReader() {
|
~HostPackageReader() {
|
||||||
@@ -345,10 +345,11 @@ namespace ams::pgl::srv {
|
|||||||
|
|
||||||
/* Get the content meta info. */
|
/* Get the content meta info. */
|
||||||
*out = {
|
*out = {
|
||||||
.id = reader.GetProgramId().value,
|
.id = reader.GetProgramId().value,
|
||||||
.version = reader.GetProgramVersion(),
|
.version = reader.GetProgramVersion(),
|
||||||
.content_type = ncm::ContentType::Program,
|
.content_type = ncm::ContentType::Program,
|
||||||
.id_offset = reader.GetProgramIndex(),
|
.id_offset = reader.GetProgramIndex(),
|
||||||
|
.content_meta_type = reader.GetContentMetaType(),
|
||||||
};
|
};
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
|||||||
@@ -104,25 +104,25 @@ namespace ams::pinmux::driver::board::nintendo::nx {
|
|||||||
#if defined(AMS_PINMUX_CONFIG_RIGHT_RAIL_AS_UART)
|
#if defined(AMS_PINMUX_CONFIG_RIGHT_RAIL_AS_UART)
|
||||||
UpdateSinglePinmuxPad({
|
UpdateSinglePinmuxPad({
|
||||||
.index = PinmuxPadIndex_Uart2Tx,
|
.index = PinmuxPadIndex_Uart2Tx,
|
||||||
.option = 0, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output */
|
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output,
|
||||||
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
|
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
|
||||||
});
|
});
|
||||||
UpdateSinglePinmuxPad({
|
UpdateSinglePinmuxPad({
|
||||||
.index = PinmuxPadIndex_Uart2Cts,
|
.index = PinmuxPadIndex_Uart2Cts,
|
||||||
.option = 0x20, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input */
|
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input,
|
||||||
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
|
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
#if defined(AMS_PINMUX_CONFIG_LEFT_RAIL_AS_UART)
|
#if defined(AMS_PINMUX_CONFIG_LEFT_RAIL_AS_UART)
|
||||||
UpdateSinglePinmuxPad({
|
UpdateSinglePinmuxPad({
|
||||||
.index = PinmuxPadIndex_Uart3Tx,
|
.index = PinmuxPadIndex_Uart3Tx,
|
||||||
.option = 0, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output */
|
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Output,
|
||||||
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
|
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
|
||||||
});
|
});
|
||||||
UpdateSinglePinmuxPad({
|
UpdateSinglePinmuxPad({
|
||||||
.index = PinmuxPadIndex_Uart3Cts,
|
.index = PinmuxPadIndex_Uart3Cts,
|
||||||
.option = 0x20, /* PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input */
|
.option = (u32)PinmuxPadPm_Pm0 | PinmuxOpt_NoPupd | PinmuxOpt_Input,
|
||||||
.option_mask = (0x7|0x18|0x60), /* PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir */
|
.option_mask = (u32)PinmuxOptBitMask_Pm | PinmuxOptBitMask_Pupd | PinmuxOptBitMask_Dir,
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,170 +24,6 @@ namespace ams::pinmux::driver::board::nintendo::nx {
|
|||||||
|
|
||||||
uintptr_t g_apb_misc_virtual_address = dd::QueryIoMapping(0x70000000, 0x4000);
|
uintptr_t g_apb_misc_virtual_address = dd::QueryIoMapping(0x70000000, 0x4000);
|
||||||
|
|
||||||
enum PinmuxPadMask : u32 {
|
|
||||||
PinmuxPadMask_Pm = 0x3,
|
|
||||||
PinmuxPadMask_Pupd = 0xC,
|
|
||||||
PinmuxPadMask_Tristate = 0x10,
|
|
||||||
PinmuxPadMask_Park = 0x20,
|
|
||||||
PinmuxPadMask_EInput = 0x40,
|
|
||||||
PinmuxPadMask_Lock = 0x80,
|
|
||||||
PinmuxPadMask_ELpdr = 0x100,
|
|
||||||
PinmuxPadMask_EHsm = 0x200,
|
|
||||||
PinmuxPadMask_EIoHv = 0x400,
|
|
||||||
PinmuxPadMask_EOd = 0x800,
|
|
||||||
PinmuxPadMask_ESchmt = 0x1000,
|
|
||||||
PinmuxPadMask_DrvType = 0x6000,
|
|
||||||
PinmuxPadMask_Preemp = 0x8000,
|
|
||||||
PinmuxPadMask_IoReset = 0x10000,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PinmuxPadBitOffset : u32 {
|
|
||||||
PinmuxPadBitOffset_Pm = 0x0,
|
|
||||||
PinmuxPadBitOffset_Pupd = 0x2,
|
|
||||||
PinmuxPadBitOffset_Tristate = 0x4,
|
|
||||||
PinmuxPadBitOffset_Park = 0x5,
|
|
||||||
PinmuxPadBitOffset_EInput = 0x6,
|
|
||||||
PinmuxPadBitOffset_Lock = 0x7,
|
|
||||||
PinmuxPadBitOffset_ELpdr = 0x8,
|
|
||||||
PinmuxPadBitOffset_EHsm = 0x9,
|
|
||||||
PinmuxPadBitOffset_EIoHv = 0xA,
|
|
||||||
PinmuxPadBitOffset_EOd = 0xB,
|
|
||||||
PinmuxPadBitOffset_ESchmt = 0xC,
|
|
||||||
PinmuxPadBitOffset_DrvType = 0xD,
|
|
||||||
PinmuxPadBitOffset_Preemp = 0xF,
|
|
||||||
PinmuxPadBitOffset_IoReset = 0x10,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PinmuxOptBitMask : u32 {
|
|
||||||
PinmuxOptBitMask_Pm = 0x7,
|
|
||||||
PinmuxOptBitMask_Pupd = 0x18,
|
|
||||||
PinmuxOptBitMask_Dir = 0x60,
|
|
||||||
PinmuxOptBitMask_Lock = 0x80,
|
|
||||||
PinmuxOptBitMask_IoReset = 0x100,
|
|
||||||
PinmuxOptBitMask_IoHv = 0x200,
|
|
||||||
PinmuxOptBitMask_Park = 0x400,
|
|
||||||
PinmuxOptBitMask_Lpdr = 0x800,
|
|
||||||
PinmuxOptBitMask_Hsm = 0x1000,
|
|
||||||
PinmuxOptBitMask_Schmt = 0x2000,
|
|
||||||
PinmuxOptBitMask_DrvType = 0xC000,
|
|
||||||
PinmuxOptBitMask_Preemp = 0x10000,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PinmuxOptBitOffset {
|
|
||||||
PinmuxOptBitOffset_Pm = 0x0,
|
|
||||||
PinmuxOptBitOffset_Pupd = 0x3,
|
|
||||||
PinmuxOptBitOffset_Dir = 0x5,
|
|
||||||
PinmuxOptBitOffset_Lock = 0x7,
|
|
||||||
PinmuxOptBitOffset_IoReset = 0x8,
|
|
||||||
PinmuxOptBitOffset_IoHv = 0x9,
|
|
||||||
PinmuxOptBitOffset_Park = 0xA,
|
|
||||||
PinmuxOptBitOffset_Lpdr = 0xB,
|
|
||||||
PinmuxOptBitOffset_Hsm = 0xC,
|
|
||||||
PinmuxOptBitOffset_Schmt = 0xD,
|
|
||||||
PinmuxOptBitOffset_DrvType = 0xE,
|
|
||||||
PinmuxOptBitOffset_Preemp = 0x10,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PinmuxDrivePadMask : u32{
|
|
||||||
PinmuxDrivePadMask_DrvDn = 0x0001F000,
|
|
||||||
PinmuxDrivePadMask_DrvUp = 0x01F00000,
|
|
||||||
PinmuxDrivePadMask_CzDrvDn = 0x0007F000,
|
|
||||||
PinmuxDrivePadMask_CzDrvUp = 0x07F00000,
|
|
||||||
PinmuxDrivePadMask_SlwR = 0x30000000,
|
|
||||||
PinmuxDrivePadMask_SlwF = 0xC0000000,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PinmuxDrivePadBitOffset : u32 {
|
|
||||||
PinmuxDrivePadBitOffset_DrvDn = 12,
|
|
||||||
PinmuxDrivePadBitOffset_DrvUp = 20,
|
|
||||||
PinmuxDrivePadBitOffset_CzDrvDn = 12,
|
|
||||||
PinmuxDrivePadBitOffset_CzDrvUp = 20,
|
|
||||||
PinmuxDrivePadBitOffset_SlwR = 28,
|
|
||||||
PinmuxDrivePadBitOffset_SlwF = 30,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PinmuxDriveOptBitMask : u32 {
|
|
||||||
PinmuxDriveOptBitMask_DrvDn = 0x0001F000,
|
|
||||||
PinmuxDriveOptBitMask_DrvUp = 0x01F00000,
|
|
||||||
PinmuxDriveOptBitMask_CzDrvDn = 0x0007F000,
|
|
||||||
PinmuxDriveOptBitMask_CzDrvUp = 0x07F00000,
|
|
||||||
PinmuxDriveOptBitMask_SlwR = 0x30000000,
|
|
||||||
PinmuxDriveOptBitMask_SlwF = 0xC0000000,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PinmuxDriveOptBitOffset : u32 {
|
|
||||||
PinmuxDriveOptBitOffset_DrvDn = 12,
|
|
||||||
PinmuxDriveOptBitOffset_DrvUp = 20,
|
|
||||||
PinmuxDriveOptBitOffset_CzDrvDn = 12,
|
|
||||||
PinmuxDriveOptBitOffset_CzDrvUp = 20,
|
|
||||||
PinmuxDriveOptBitOffset_SlwR = 28,
|
|
||||||
PinmuxDriveOptBitOffset_SlwF = 30,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PinmuxOpt : u32 {
|
|
||||||
/* Pm */
|
|
||||||
PinmuxOpt_Gpio = 0x4,
|
|
||||||
PinmuxOpt_Unused = 0x5,
|
|
||||||
|
|
||||||
/* Pupd */
|
|
||||||
PinmuxOpt_NoPupd = 0x0,
|
|
||||||
PinmuxOpt_PullDown = 0x8,
|
|
||||||
PinmuxOpt_PullUp = 0x10,
|
|
||||||
|
|
||||||
/* Dir */
|
|
||||||
PinmuxOpt_Output = 0x0,
|
|
||||||
PinmuxOpt_Input = 0x20,
|
|
||||||
PinmuxOpt_Bidirection = 0x40,
|
|
||||||
PinmuxOpt_OpenDrain = 0x60,
|
|
||||||
|
|
||||||
/* Lock */
|
|
||||||
PinmuxOpt_Unlock = 0x0,
|
|
||||||
PinmuxOpt_Lock = 0x80,
|
|
||||||
|
|
||||||
/* IoReset */
|
|
||||||
PinmuxOpt_DisableIoReset = 0x0,
|
|
||||||
PinmuxOpt_EnableIoReset = 0x100,
|
|
||||||
|
|
||||||
/* IoHv */
|
|
||||||
PinmuxOpt_NormalVoltage = 0x0,
|
|
||||||
PinmuxOpt_HighVoltage = 0x200,
|
|
||||||
|
|
||||||
/* Park */
|
|
||||||
PinmuxOpt_ResetOnLowPower = 0x0,
|
|
||||||
PinmuxOpt_ParkOnLowPower = 0x400,
|
|
||||||
|
|
||||||
/* Lpdr */
|
|
||||||
PinmuxOpt_DisableBaseDriver = 0x0,
|
|
||||||
PinmuxOpt_EnableBaseDriver = 0x800,
|
|
||||||
|
|
||||||
/* Hsm */
|
|
||||||
PinmuxOpt_DisableHighSpeedMode = 0x0,
|
|
||||||
PinmuxOpt_EnableHighSpeedMode = 0x1000,
|
|
||||||
|
|
||||||
/* Schmt */
|
|
||||||
PinmuxOpt_CmosMode = 0x0,
|
|
||||||
PinmuxOpt_SchmittTrigger = 0x2000,
|
|
||||||
|
|
||||||
/* DrvType */
|
|
||||||
PinmuxOpt_DrvType1X = 0x0,
|
|
||||||
PinmuxOpt_DrvType2X = 0x4000,
|
|
||||||
PinmuxOpt_DrvType3X = 0x8000,
|
|
||||||
PinmuxOpt_DrvType4X = 0xC000,
|
|
||||||
|
|
||||||
/* Preemp */
|
|
||||||
PinmuxOpt_DisablePreemp = 0x0,
|
|
||||||
PinmuxOpt_EnablePreemp = 0x10000,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PinmuxPadPm : u32 {
|
|
||||||
PinmuxPadPm_Default = 0xFFFFFFFF,
|
|
||||||
PinmuxPadPm_Pm0 = 0x0,
|
|
||||||
PinmuxPadPm_Pm1 = 0x1,
|
|
||||||
PinmuxPadPm_Pm2 = 0x2,
|
|
||||||
PinmuxPadPm_Pm3 = 0x3,
|
|
||||||
PinmuxPadPm_Safe = 0x4,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PinmuxPadCharacter {
|
struct PinmuxPadCharacter {
|
||||||
u32 reg_offset;
|
u32 reg_offset;
|
||||||
u32 reg_mask;
|
u32 reg_mask;
|
||||||
|
|||||||
@@ -30,6 +30,170 @@ namespace ams::pinmux::driver::board::nintendo::nx {
|
|||||||
u32 option_mask;
|
u32 option_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PinmuxPadMask : u32 {
|
||||||
|
PinmuxPadMask_Pm = 0x3,
|
||||||
|
PinmuxPadMask_Pupd = 0xC,
|
||||||
|
PinmuxPadMask_Tristate = 0x10,
|
||||||
|
PinmuxPadMask_Park = 0x20,
|
||||||
|
PinmuxPadMask_EInput = 0x40,
|
||||||
|
PinmuxPadMask_Lock = 0x80,
|
||||||
|
PinmuxPadMask_ELpdr = 0x100,
|
||||||
|
PinmuxPadMask_EHsm = 0x200,
|
||||||
|
PinmuxPadMask_EIoHv = 0x400,
|
||||||
|
PinmuxPadMask_EOd = 0x800,
|
||||||
|
PinmuxPadMask_ESchmt = 0x1000,
|
||||||
|
PinmuxPadMask_DrvType = 0x6000,
|
||||||
|
PinmuxPadMask_Preemp = 0x8000,
|
||||||
|
PinmuxPadMask_IoReset = 0x10000,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PinmuxPadBitOffset : u32 {
|
||||||
|
PinmuxPadBitOffset_Pm = 0x0,
|
||||||
|
PinmuxPadBitOffset_Pupd = 0x2,
|
||||||
|
PinmuxPadBitOffset_Tristate = 0x4,
|
||||||
|
PinmuxPadBitOffset_Park = 0x5,
|
||||||
|
PinmuxPadBitOffset_EInput = 0x6,
|
||||||
|
PinmuxPadBitOffset_Lock = 0x7,
|
||||||
|
PinmuxPadBitOffset_ELpdr = 0x8,
|
||||||
|
PinmuxPadBitOffset_EHsm = 0x9,
|
||||||
|
PinmuxPadBitOffset_EIoHv = 0xA,
|
||||||
|
PinmuxPadBitOffset_EOd = 0xB,
|
||||||
|
PinmuxPadBitOffset_ESchmt = 0xC,
|
||||||
|
PinmuxPadBitOffset_DrvType = 0xD,
|
||||||
|
PinmuxPadBitOffset_Preemp = 0xF,
|
||||||
|
PinmuxPadBitOffset_IoReset = 0x10,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PinmuxOptBitMask : u32 {
|
||||||
|
PinmuxOptBitMask_Pm = 0x7,
|
||||||
|
PinmuxOptBitMask_Pupd = 0x18,
|
||||||
|
PinmuxOptBitMask_Dir = 0x60,
|
||||||
|
PinmuxOptBitMask_Lock = 0x80,
|
||||||
|
PinmuxOptBitMask_IoReset = 0x100,
|
||||||
|
PinmuxOptBitMask_IoHv = 0x200,
|
||||||
|
PinmuxOptBitMask_Park = 0x400,
|
||||||
|
PinmuxOptBitMask_Lpdr = 0x800,
|
||||||
|
PinmuxOptBitMask_Hsm = 0x1000,
|
||||||
|
PinmuxOptBitMask_Schmt = 0x2000,
|
||||||
|
PinmuxOptBitMask_DrvType = 0xC000,
|
||||||
|
PinmuxOptBitMask_Preemp = 0x10000,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PinmuxOptBitOffset {
|
||||||
|
PinmuxOptBitOffset_Pm = 0x0,
|
||||||
|
PinmuxOptBitOffset_Pupd = 0x3,
|
||||||
|
PinmuxOptBitOffset_Dir = 0x5,
|
||||||
|
PinmuxOptBitOffset_Lock = 0x7,
|
||||||
|
PinmuxOptBitOffset_IoReset = 0x8,
|
||||||
|
PinmuxOptBitOffset_IoHv = 0x9,
|
||||||
|
PinmuxOptBitOffset_Park = 0xA,
|
||||||
|
PinmuxOptBitOffset_Lpdr = 0xB,
|
||||||
|
PinmuxOptBitOffset_Hsm = 0xC,
|
||||||
|
PinmuxOptBitOffset_Schmt = 0xD,
|
||||||
|
PinmuxOptBitOffset_DrvType = 0xE,
|
||||||
|
PinmuxOptBitOffset_Preemp = 0x10,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PinmuxDrivePadMask : u32 {
|
||||||
|
PinmuxDrivePadMask_DrvDn = 0x0001F000,
|
||||||
|
PinmuxDrivePadMask_DrvUp = 0x01F00000,
|
||||||
|
PinmuxDrivePadMask_CzDrvDn = 0x0007F000,
|
||||||
|
PinmuxDrivePadMask_CzDrvUp = 0x07F00000,
|
||||||
|
PinmuxDrivePadMask_SlwR = 0x30000000,
|
||||||
|
PinmuxDrivePadMask_SlwF = 0xC0000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PinmuxDrivePadBitOffset : u32 {
|
||||||
|
PinmuxDrivePadBitOffset_DrvDn = 12,
|
||||||
|
PinmuxDrivePadBitOffset_DrvUp = 20,
|
||||||
|
PinmuxDrivePadBitOffset_CzDrvDn = 12,
|
||||||
|
PinmuxDrivePadBitOffset_CzDrvUp = 20,
|
||||||
|
PinmuxDrivePadBitOffset_SlwR = 28,
|
||||||
|
PinmuxDrivePadBitOffset_SlwF = 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PinmuxDriveOptBitMask : u32 {
|
||||||
|
PinmuxDriveOptBitMask_DrvDn = 0x0001F000,
|
||||||
|
PinmuxDriveOptBitMask_DrvUp = 0x01F00000,
|
||||||
|
PinmuxDriveOptBitMask_CzDrvDn = 0x0007F000,
|
||||||
|
PinmuxDriveOptBitMask_CzDrvUp = 0x07F00000,
|
||||||
|
PinmuxDriveOptBitMask_SlwR = 0x30000000,
|
||||||
|
PinmuxDriveOptBitMask_SlwF = 0xC0000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PinmuxDriveOptBitOffset : u32 {
|
||||||
|
PinmuxDriveOptBitOffset_DrvDn = 12,
|
||||||
|
PinmuxDriveOptBitOffset_DrvUp = 20,
|
||||||
|
PinmuxDriveOptBitOffset_CzDrvDn = 12,
|
||||||
|
PinmuxDriveOptBitOffset_CzDrvUp = 20,
|
||||||
|
PinmuxDriveOptBitOffset_SlwR = 28,
|
||||||
|
PinmuxDriveOptBitOffset_SlwF = 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PinmuxOpt : u32 {
|
||||||
|
/* Pm */
|
||||||
|
PinmuxOpt_Gpio = 0x4,
|
||||||
|
PinmuxOpt_Unused = 0x5,
|
||||||
|
|
||||||
|
/* Pupd */
|
||||||
|
PinmuxOpt_NoPupd = 0x0,
|
||||||
|
PinmuxOpt_PullDown = 0x8,
|
||||||
|
PinmuxOpt_PullUp = 0x10,
|
||||||
|
|
||||||
|
/* Dir */
|
||||||
|
PinmuxOpt_Output = 0x0,
|
||||||
|
PinmuxOpt_Input = 0x20,
|
||||||
|
PinmuxOpt_Bidirection = 0x40,
|
||||||
|
PinmuxOpt_OpenDrain = 0x60,
|
||||||
|
|
||||||
|
/* Lock */
|
||||||
|
PinmuxOpt_Unlock = 0x0,
|
||||||
|
PinmuxOpt_Lock = 0x80,
|
||||||
|
|
||||||
|
/* IoReset */
|
||||||
|
PinmuxOpt_DisableIoReset = 0x0,
|
||||||
|
PinmuxOpt_EnableIoReset = 0x100,
|
||||||
|
|
||||||
|
/* IoHv */
|
||||||
|
PinmuxOpt_NormalVoltage = 0x0,
|
||||||
|
PinmuxOpt_HighVoltage = 0x200,
|
||||||
|
|
||||||
|
/* Park */
|
||||||
|
PinmuxOpt_ResetOnLowPower = 0x0,
|
||||||
|
PinmuxOpt_ParkOnLowPower = 0x400,
|
||||||
|
|
||||||
|
/* Lpdr */
|
||||||
|
PinmuxOpt_DisableBaseDriver = 0x0,
|
||||||
|
PinmuxOpt_EnableBaseDriver = 0x800,
|
||||||
|
|
||||||
|
/* Hsm */
|
||||||
|
PinmuxOpt_DisableHighSpeedMode = 0x0,
|
||||||
|
PinmuxOpt_EnableHighSpeedMode = 0x1000,
|
||||||
|
|
||||||
|
/* Schmt */
|
||||||
|
PinmuxOpt_CmosMode = 0x0,
|
||||||
|
PinmuxOpt_SchmittTrigger = 0x2000,
|
||||||
|
|
||||||
|
/* DrvType */
|
||||||
|
PinmuxOpt_DrvType1X = 0x0,
|
||||||
|
PinmuxOpt_DrvType2X = 0x4000,
|
||||||
|
PinmuxOpt_DrvType3X = 0x8000,
|
||||||
|
PinmuxOpt_DrvType4X = 0xC000,
|
||||||
|
|
||||||
|
/* Preemp */
|
||||||
|
PinmuxOpt_DisablePreemp = 0x0,
|
||||||
|
PinmuxOpt_EnablePreemp = 0x10000,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PinmuxPadPm : u32 {
|
||||||
|
PinmuxPadPm_Default = 0xFFFFFFFF,
|
||||||
|
PinmuxPadPm_Pm0 = 0x0,
|
||||||
|
PinmuxPadPm_Pm1 = 0x1,
|
||||||
|
PinmuxPadPm_Pm2 = 0x2,
|
||||||
|
PinmuxPadPm_Pm3 = 0x3,
|
||||||
|
PinmuxPadPm_Safe = 0x4,
|
||||||
|
};
|
||||||
|
|
||||||
void InitializePlatformPads();
|
void InitializePlatformPads();
|
||||||
|
|
||||||
void UpdateSinglePinmuxPad(const PinmuxPadConfig &config);
|
void UpdateSinglePinmuxPad(const PinmuxPadConfig &config);
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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>
|
||||||
|
#include "lz4.h"
|
||||||
|
|
||||||
|
namespace ams::util {
|
||||||
|
|
||||||
|
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
|
/* Size checks. */
|
||||||
|
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
|
||||||
|
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
|
||||||
|
|
||||||
|
/* This is just a thin wrapper around LZ4. */
|
||||||
|
return LZ4_compress_default(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
|
/* Size checks. */
|
||||||
|
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
|
||||||
|
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
|
||||||
|
|
||||||
|
/* This is just a thin wrapper around LZ4. */
|
||||||
|
return LZ4_decompress_safe(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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>
|
||||||
|
#define ZSTD_STATIC_LINKING_ONLY
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||||
|
#define ZSTDLIB_VISIBLE static
|
||||||
|
#define ZSTDLIB_HIDDEN static
|
||||||
|
#include "zstd.h"
|
||||||
|
#include "zstd.inc"
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
namespace ams::util {
|
||||||
|
|
||||||
|
size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
|
/* Basic size checks. */
|
||||||
|
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
|
||||||
|
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
|
||||||
|
|
||||||
|
/* Additionally, we must check the compression boundary. */
|
||||||
|
auto bound = ZSTD_compressBound(src_size);
|
||||||
|
AMS_ABORT_UNLESS(!ZSTD_isError(bound));
|
||||||
|
AMS_ABORT_UNLESS(dst_size >= bound);
|
||||||
|
|
||||||
|
/* Use Zstd default level. */
|
||||||
|
int compressionLevel = 3;
|
||||||
|
|
||||||
|
/* This is just a wrapper around Zstd. */
|
||||||
|
return ZSTD_compress(dst, dst_size, src, src_size, compressionLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
|
/* Basic size checks. */
|
||||||
|
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
|
||||||
|
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
|
||||||
|
|
||||||
|
/* Additionally, we must check the decompression boundary. */
|
||||||
|
auto bound = ZSTD_decompressBound(src, src_size);
|
||||||
|
AMS_ABORT_UNLESS(!ZSTD_isError(bound));
|
||||||
|
AMS_ABORT_UNLESS(dst_size >= bound);
|
||||||
|
|
||||||
|
/* This is just a wrapper around Zstd. */
|
||||||
|
return ZSTD_decompress(dst, dst_size, src, src_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -14,24 +14,21 @@
|
|||||||
* 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 <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "lz4.h"
|
|
||||||
#define ZSTD_STATIC_LINKING_ONLY
|
#define ZSTD_STATIC_LINKING_ONLY
|
||||||
#define ZSTD_ZBIC_SUPPORT 1
|
#define ZSTD_ZBIC_SUPPORT 1
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||||
|
#define ZSTDLIB_VISIBLE static
|
||||||
|
#define ZSTDLIB_HIDDEN static
|
||||||
#include "zstd.h"
|
#include "zstd.h"
|
||||||
|
#include "zstd.inc"
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
namespace ams::util {
|
namespace ams::util {
|
||||||
|
static_assert(sizeof(ZSTD_DCtx) <= DecompressZstdWithBicWorkBufferSizeDefault);
|
||||||
|
|
||||||
/* Compression utilities. */
|
size_t CompressZstdWithBic(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
int CompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
||||||
/* Size checks. */
|
|
||||||
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
|
|
||||||
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
|
|
||||||
|
|
||||||
/* This is just a thin wrapper around LZ4. */
|
|
||||||
return LZ4_compress_default(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
||||||
/* Basic size checks. */
|
/* Basic size checks. */
|
||||||
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
|
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
|
||||||
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
|
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
|
||||||
@@ -44,21 +41,11 @@ namespace ams::util {
|
|||||||
/* Use Zstd default level. */
|
/* Use Zstd default level. */
|
||||||
int compressionLevel = 3;
|
int compressionLevel = 3;
|
||||||
|
|
||||||
/* This is just a wrapper around Zstd. */
|
/* This is just a wrapper around Zstd with BIC support enabled. */
|
||||||
return ZSTD_compress(dst, dst_size, src, src_size, compressionLevel);
|
return ZSTD_compress(dst, dst_size, src, src_size, compressionLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decompression utilities. */
|
|
||||||
int DecompressLZ4(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
||||||
/* Size checks. */
|
|
||||||
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
|
|
||||||
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
|
|
||||||
|
|
||||||
/* This is just a thin wrapper around LZ4. */
|
|
||||||
return LZ4_decompress_safe(reinterpret_cast<const char *>(src), reinterpret_cast<char *>(dst), static_cast<int>(src_size), static_cast<int>(dst_size));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t DecompressZstd(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
size_t DecompressZstdWithBic(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
/* Basic size checks. */
|
/* Basic size checks. */
|
||||||
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
|
AMS_ABORT_UNLESS(dst_size <= std::numeric_limits<int>::max());
|
||||||
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
|
AMS_ABORT_UNLESS(src_size <= std::numeric_limits<int>::max());
|
||||||
@@ -68,14 +55,22 @@ namespace ams::util {
|
|||||||
AMS_ABORT_UNLESS(!ZSTD_isError(bound));
|
AMS_ABORT_UNLESS(!ZSTD_isError(bound));
|
||||||
AMS_ABORT_UNLESS(dst_size >= bound);
|
AMS_ABORT_UNLESS(dst_size >= bound);
|
||||||
|
|
||||||
/* This is just a wrapper around Zstd. */
|
/* This is just a wrapper around Zstd with BIC support enabled. */
|
||||||
return ZSTD_decompress(dst, dst_size, src, src_size);
|
return ZSTD_decompress(dst, dst_size, src, src_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecompressZstdForLoader(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size) {
|
bool DecompressZstdWithBic(void* workspace, size_t workspace_size, void *dst, size_t dst_size, size_t expected_dec_size, const void *src, size_t src_size) {
|
||||||
/* Check decompression margin. */
|
/* Check decompression margin. */
|
||||||
auto margin = ZSTD_decompressionMargin(src, src_size);
|
auto margin = ZSTD_decompressionMargin(src, src_size);
|
||||||
if (ZSTD_isError(margin)) {
|
if (ZSTD_isError(margin)) {
|
||||||
|
auto error_code = ZSTD_getErrorCode(margin);
|
||||||
|
auto error_string = ZSTD_getErrorString(error_code);
|
||||||
|
|
||||||
|
AMS_LOG("[util] Can't determine decompression margin: %u (%s)\n", error_code, error_string);
|
||||||
|
|
||||||
|
/* TODO: Unused variables in non-debug build. */
|
||||||
|
AMS_UNUSED(error_code, error_string);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,20 +81,30 @@ namespace ams::util {
|
|||||||
|
|
||||||
/* Make sure we fit in the destination buffer. */
|
/* Make sure we fit in the destination buffer. */
|
||||||
if (margin + expected_dec_size > dst_size) {
|
if (margin + expected_dec_size > dst_size) {
|
||||||
|
AMS_LOG("[util] Not enough space for decompression %lu + %lu > %lu\n", margin, expected_dec_size, dst_size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a runtime assert in Loader code. We replicate it here. */
|
/* This is a runtime assert in Loader code. Note that Nintendo does == comparison here. */
|
||||||
AMS_ABORT_UNLESS(ZSTD_estimateDCtxSize() == workspace_size);
|
AMS_ABORT_UNLESS(ZSTD_estimateDCtxSize() <= workspace_size);
|
||||||
|
|
||||||
/* Decompress using a static decompression context. */
|
/* Decompress using a static decompression context. */
|
||||||
auto dctx = ZSTD_initStaticDCtx(workspace, workspace_size);
|
auto dctx = ZSTD_initStaticDCtx(workspace, workspace_size);
|
||||||
size_t dec_size = ZSTD_decompressDCtx(dctx, dst, dst_size, src, src_size);
|
size_t dec_size = ZSTD_decompressDCtx(dctx, dst, dst_size, src, src_size);
|
||||||
|
|
||||||
if (ZSTD_isError(dec_size)) {
|
if (ZSTD_isError(dec_size)) {
|
||||||
|
auto error_code = ZSTD_getErrorCode(margin);
|
||||||
|
auto error_string = ZSTD_getErrorString(error_code);
|
||||||
|
|
||||||
|
AMS_LOG("[util] Decompression failed: %u (%s)\n", error_code, error_string);
|
||||||
|
|
||||||
|
/* TODO: Unused variables in non-debug build. */
|
||||||
|
AMS_UNUSED(error_code, error_string);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure we match the expected size. */
|
||||||
if (dec_size != expected_dec_size) {
|
if (dec_size != expected_dec_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -17,10 +17,10 @@
|
|||||||
|
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
|
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 11
|
#define ATMOSPHERE_RELEASE_VERSION_MINOR 11
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
|
#define ATMOSPHERE_RELEASE_VERSION_MICRO 2
|
||||||
|
|
||||||
#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 22
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 22
|
||||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 5
|
||||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
||||||
|
|||||||
@@ -99,8 +99,10 @@
|
|||||||
#define ATMOSPHERE_TARGET_FIRMWARE_21_1_0 ATMOSPHERE_TARGET_FIRMWARE(21, 1, 0)
|
#define ATMOSPHERE_TARGET_FIRMWARE_21_1_0 ATMOSPHERE_TARGET_FIRMWARE(21, 1, 0)
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_21_2_0 ATMOSPHERE_TARGET_FIRMWARE(21, 2, 0)
|
#define ATMOSPHERE_TARGET_FIRMWARE_21_2_0 ATMOSPHERE_TARGET_FIRMWARE(21, 2, 0)
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_22_0_0 ATMOSPHERE_TARGET_FIRMWARE(22, 0, 0)
|
#define ATMOSPHERE_TARGET_FIRMWARE_22_0_0 ATMOSPHERE_TARGET_FIRMWARE(22, 0, 0)
|
||||||
|
#define ATMOSPHERE_TARGET_FIRMWARE_22_1_0 ATMOSPHERE_TARGET_FIRMWARE(22, 1, 0)
|
||||||
|
#define ATMOSPHERE_TARGET_FIRMWARE_22_5_0 ATMOSPHERE_TARGET_FIRMWARE(22, 5, 0)
|
||||||
|
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_22_0_0
|
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_22_5_0
|
||||||
|
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
|
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
||||||
@@ -192,6 +194,8 @@ namespace ams {
|
|||||||
TargetFirmware_21_1_0 = ATMOSPHERE_TARGET_FIRMWARE_21_1_0,
|
TargetFirmware_21_1_0 = ATMOSPHERE_TARGET_FIRMWARE_21_1_0,
|
||||||
TargetFirmware_21_2_0 = ATMOSPHERE_TARGET_FIRMWARE_21_2_0,
|
TargetFirmware_21_2_0 = ATMOSPHERE_TARGET_FIRMWARE_21_2_0,
|
||||||
TargetFirmware_22_0_0 = ATMOSPHERE_TARGET_FIRMWARE_22_0_0,
|
TargetFirmware_22_0_0 = ATMOSPHERE_TARGET_FIRMWARE_22_0_0,
|
||||||
|
TargetFirmware_22_1_0 = ATMOSPHERE_TARGET_FIRMWARE_22_1_0,
|
||||||
|
TargetFirmware_22_5_0 = ATMOSPHERE_TARGET_FIRMWARE_22_5_0,
|
||||||
|
|
||||||
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,
|
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,
|
||||||
|
|
||||||
|
|||||||
@@ -452,6 +452,9 @@ namespace ams::result::impl {
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Explicitly discards the result returned by an expression.
|
||||||
|
#define R_DISCARD(res_expr) (static_cast<void>(res_expr))
|
||||||
|
|
||||||
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_IS_STRATOSPHERE) && !defined(AMS_ENABLE_DETAILED_ASSERTIONS) && !defined(AMS_BUILD_FOR_DEBUGGING) && !defined(AMS_BUILD_FOR_AUDITING)
|
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_IS_STRATOSPHERE) && !defined(AMS_ENABLE_DETAILED_ASSERTIONS) && !defined(AMS_BUILD_FOR_DEBUGGING) && !defined(AMS_BUILD_FOR_AUDITING)
|
||||||
#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false)
|
#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false)
|
||||||
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false)
|
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false)
|
||||||
@@ -491,6 +494,14 @@ namespace ams::result::impl {
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define R_UNLESS_LOG(expr, res, ...) \
|
||||||
|
{ \
|
||||||
|
if (!(expr)) { \
|
||||||
|
AMS_LOG(__VA_ARGS__); \
|
||||||
|
R_THROW(res); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
/// Evaluates a boolean expression, and succeeds if that expression is true.
|
/// Evaluates a boolean expression, and succeeds if that expression is true.
|
||||||
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess())
|
#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), ResultSuccess())
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,10 @@ namespace ams::svc::codegen::impl {
|
|||||||
/* Process all arguments, in order. */
|
/* Process all arguments, in order. */
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
(layout.ProcessArgument<AbiType, ArgumentTypes>(i++, NGRN, NSAA), ...);
|
(layout.ProcessArgument<AbiType, ArgumentTypes>(i++, NGRN, NSAA), ...);
|
||||||
|
|
||||||
|
/* TODO: Unused variable. */
|
||||||
|
AMS_UNUSED(i);
|
||||||
|
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ namespace ams::mitm::fs {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr const ApplicationWithDynamicHeapInfo ApplicationsWithDynamicHeap[] = {
|
constexpr const ApplicationWithDynamicHeapInfo ApplicationsWithDynamicHeap[] = {
|
||||||
|
/* Until Then. */
|
||||||
|
/* Requirement ~34 MB. */
|
||||||
|
/* No particular heap sensitivity. */
|
||||||
|
{ 0x010019C023004000, 16_MB, 0_MB },
|
||||||
|
|
||||||
/* Trails in the Sky 1st Chapter. */
|
/* Trails in the Sky 1st Chapter. */
|
||||||
/* Requirement ? MB. 16 MB stolen heap fixes a crash, though. */
|
/* Requirement ? MB. 16 MB stolen heap fixes a crash, though. */
|
||||||
/* Unknown heap sensitivity. */
|
/* Unknown heap sensitivity. */
|
||||||
|
|||||||
@@ -100,5 +100,6 @@ constexpr inline const EmbeddedPatch Usb30ForceEnablePatches[] = {
|
|||||||
{ ParseModuleId("40E80E7442C0DFC985315E6F9E8C77229818AC0F"), util::size(Usb30ForceEnablePatches_20_0_0), Usb30ForceEnablePatches_20_0_0 }, /* 20.0.0 */
|
{ ParseModuleId("40E80E7442C0DFC985315E6F9E8C77229818AC0F"), util::size(Usb30ForceEnablePatches_20_0_0), Usb30ForceEnablePatches_20_0_0 }, /* 20.0.0 */
|
||||||
{ ParseModuleId("A5EF8D22EDF8A384E4135270ED596C1D2D524159"), util::size(Usb30ForceEnablePatches_20_0_0), Usb30ForceEnablePatches_20_0_0 }, /* 20.1.0 - 20.5.0 */
|
{ ParseModuleId("A5EF8D22EDF8A384E4135270ED596C1D2D524159"), util::size(Usb30ForceEnablePatches_20_0_0), Usb30ForceEnablePatches_20_0_0 }, /* 20.1.0 - 20.5.0 */
|
||||||
{ ParseModuleId("766D0C2277207B40AD9B8DE309396D50CCE94885"), util::size(Usb30ForceEnablePatches_21_0_0), Usb30ForceEnablePatches_21_0_0 }, /* 21.0.0 */
|
{ ParseModuleId("766D0C2277207B40AD9B8DE309396D50CCE94885"), util::size(Usb30ForceEnablePatches_21_0_0), Usb30ForceEnablePatches_21_0_0 }, /* 21.0.0 */
|
||||||
{ ParseModuleId("B734339F2280170AF0200573F9B943242CEF8C15"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.0.0 */
|
{ ParseModuleId("B734339F2280170AF0200573F9B943242CEF8C15"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.0.0 - 22.1.0 */
|
||||||
|
{ ParseModuleId("AD8D36F2029822A4C498F055ADBDAA789EB913C6"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.5.0 */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -121,8 +121,7 @@ namespace ams::ldr {
|
|||||||
NsoHeader g_nso_headers[Nso_Count];
|
NsoHeader g_nso_headers[Nso_Count];
|
||||||
|
|
||||||
/* Global Zstd decompression context. */
|
/* Global Zstd decompression context. */
|
||||||
constexpr size_t ZstdDctxWorkspaceSize = 0x176E8;
|
alignas(8) u8 g_zstd_dctx_workspace[util::DecompressZstdWithBicWorkBufferSizeDefault];
|
||||||
alignas(8) u8 g_zstd_dctx_workspace[ZstdDctxWorkspaceSize];
|
|
||||||
|
|
||||||
Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) {
|
Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) {
|
||||||
/* No version verification is done before 8.1.0. */
|
/* No version verification is done before 8.1.0. */
|
||||||
@@ -220,7 +219,7 @@ namespace ams::ldr {
|
|||||||
/* Read NSO header. */
|
/* Read NSO header. */
|
||||||
size_t read_size;
|
size_t read_size;
|
||||||
R_TRY(fs::ReadFile(std::addressof(read_size), file, 0, g_nso_headers + ctx.nso_count, sizeof(NsoHeader)));
|
R_TRY(fs::ReadFile(std::addressof(read_size), file, 0, g_nso_headers + ctx.nso_count, sizeof(NsoHeader)));
|
||||||
R_UNLESS(read_size == sizeof(NsoHeader), ldr::ResultInvalidNso());
|
R_UNLESS_LOG(read_size == sizeof(NsoHeader), ldr::ResultInvalidNso(), "[ldr] NSO header truncated!\n");
|
||||||
|
|
||||||
/* Note nso is present. */
|
/* Note nso is present. */
|
||||||
switch (i) {
|
switch (i) {
|
||||||
@@ -259,7 +258,7 @@ namespace ams::ldr {
|
|||||||
|
|
||||||
Result CheckAutoLoad(const AutoLoadModuleContext &ctx, u32 acid_flags) {
|
Result CheckAutoLoad(const AutoLoadModuleContext &ctx, u32 acid_flags) {
|
||||||
/* We must always have a main. */
|
/* We must always have a main. */
|
||||||
R_UNLESS(ctx.ali.has_main, ldr::ResultInvalidNso());
|
R_UNLESS_LOG(ctx.ali.has_main, ldr::ResultInvalidNso(), "[ldr] Missing main!\n");
|
||||||
|
|
||||||
/* Validate flags and extents for all present NSOs. */
|
/* Validate flags and extents for all present NSOs. */
|
||||||
for (int i = 0; i < ctx.nso_count; ++i) {
|
for (int i = 0; i < ctx.nso_count; ++i) {
|
||||||
@@ -267,11 +266,11 @@ namespace ams::ldr {
|
|||||||
|
|
||||||
/* All NSOs must not be --X. */
|
/* All NSOs must not be --X. */
|
||||||
/* This is "probably" not checked on Ounce? */
|
/* This is "probably" not checked on Ounce? */
|
||||||
R_UNLESS((hdr.flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso());
|
R_UNLESS_LOG((hdr.flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso(), "[ldr] NSO[%d] --x not allowed!\n", i);
|
||||||
|
|
||||||
/* Zstd compression only allowed on main, and only when both rtld+sdk are present. */
|
/* Zstd compression only allowed on main, and only when both rtld+sdk are present. */
|
||||||
if (i != ctx.main_nso_idx || ctx.rtld_idx < 0 || ctx.sdk_nso_idx < 0) {
|
if (i != ctx.main_nso_idx || ctx.rtld_idx < 0 || ctx.sdk_nso_idx < 0) {
|
||||||
R_UNLESS((hdr.flags & NsoHeader::Flag_UseZbicCompression) == 0, ldr::ResultInvalidNso());
|
R_UNLESS_LOG((hdr.flags & NsoHeader::Flag_UseZbicCompression) == 0, ldr::ResultInvalidNso(), "[ldr] NSO[%d] zbic not allowed!\n", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NSOs must have page-aligned segments. */
|
/* NSOs must have page-aligned segments. */
|
||||||
@@ -294,13 +293,13 @@ namespace ams::ldr {
|
|||||||
const bool has_browser_dll = (acid_flags & Acid::AcidFlag_LoadBrowserCoreDll) != 0;
|
const bool has_browser_dll = (acid_flags & Acid::AcidFlag_LoadBrowserCoreDll) != 0;
|
||||||
if (ctx.ali.has_rtld || ctx.ali.has_sdk) {
|
if (ctx.ali.has_rtld || ctx.ali.has_sdk) {
|
||||||
/* If we have sdk we must have rtld. */
|
/* If we have sdk we must have rtld. */
|
||||||
R_UNLESS(ctx.ali.has_rtld, ldr::ResultInvalidNso());
|
R_UNLESS_LOG(ctx.ali.has_rtld, ldr::ResultInvalidNso(), "[ldr] Missing rtld!\n");
|
||||||
|
|
||||||
/* If we have rtld, we must not have browser core dll. */
|
/* If we have rtld, we must not have browser core dll. */
|
||||||
R_UNLESS(!has_browser_dll, ldr::ResultInvalidNso());
|
R_UNLESS_LOG(!has_browser_dll, ldr::ResultInvalidNso(), "[ldr] BrowserCoreDll must not be present!\n");
|
||||||
} else {
|
} else {
|
||||||
/* We must not have both subsdk and browser dll. */
|
/* We must not have both subsdk and browser dll. */
|
||||||
R_UNLESS(!(ctx.ali.has_subsdk && has_browser_dll), ldr::ResultInvalidNso());
|
R_UNLESS_LOG(!(ctx.ali.has_subsdk && has_browser_dll), ldr::ResultInvalidNso(), "[ldr] Can't have both subsdk and BrowserCoreDll!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@@ -385,6 +384,8 @@ namespace ams::ldr {
|
|||||||
|
|
||||||
/* If the signature check fails, we need to check if this is allowable. */
|
/* If the signature check fails, we need to check if this is allowable. */
|
||||||
if (!is_signature_valid) {
|
if (!is_signature_valid) {
|
||||||
|
AMS_LOG("[ldr] invalid signature!\n");
|
||||||
|
|
||||||
/* We have to enforce signature checks on prod and when we have a signature to check on dev. */
|
/* We have to enforce signature checks on prod and when we have a signature to check on dev. */
|
||||||
R_UNLESS(IsDevelopmentForAcidProductionCheck(), ldr::ResultInvalidNcaSignature());
|
R_UNLESS(IsDevelopmentForAcidProductionCheck(), ldr::ResultInvalidNcaSignature());
|
||||||
R_UNLESS(!code_verification_data.has_data, ldr::ResultInvalidNcaSignature());
|
R_UNLESS(!code_verification_data.has_data, ldr::ResultInvalidNcaSignature());
|
||||||
@@ -635,10 +636,13 @@ namespace ams::ldr {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoadAutoLoadModuleSegment(fs::FileHandle file, size_t file_offset, size_t compressed_size, size_t segment_size, bool is_compressed, bool is_zstd, uintptr_t map_base, uintptr_t map_end) {
|
Result LoadAutoLoadModuleSegment(fs::FileHandle file, size_t file_offset, size_t compressed_size, size_t segment_size, bool is_compressed, bool is_zbic, uintptr_t map_base, uintptr_t map_end) {
|
||||||
/* Select read size based on compression. */
|
/* Select read size based on compression. */
|
||||||
size_t file_size = is_compressed ? compressed_size : segment_size;
|
size_t file_size = is_compressed ? compressed_size : segment_size;
|
||||||
|
|
||||||
|
AMS_LOG("[ldr] Loading segment @ 0x%016lx: compressed=%d, file_size=0x%08lx, compressed_size=0x%08lx, segment_size=0x%08lx\n",
|
||||||
|
map_base, is_compressed, file_size, compressed_size, segment_size);
|
||||||
|
|
||||||
/* Validate size. */
|
/* Validate size. */
|
||||||
R_UNLESS(file_size <= segment_size, ldr::ResultInvalidNso());
|
R_UNLESS(file_size <= segment_size, ldr::ResultInvalidNso());
|
||||||
R_UNLESS(file_size <= std::numeric_limits<s32>::max(), ldr::ResultInvalidNso());
|
R_UNLESS(file_size <= std::numeric_limits<s32>::max(), ldr::ResultInvalidNso());
|
||||||
@@ -648,19 +652,19 @@ namespace ams::ldr {
|
|||||||
uintptr_t load_address = is_compressed ? map_end - compressed_size : map_base;
|
uintptr_t load_address = is_compressed ? map_end - compressed_size : map_base;
|
||||||
size_t read_size;
|
size_t read_size;
|
||||||
R_TRY(fs::ReadFile(std::addressof(read_size), file, file_offset, reinterpret_cast<void *>(load_address), file_size));
|
R_TRY(fs::ReadFile(std::addressof(read_size), file, file_offset, reinterpret_cast<void *>(load_address), file_size));
|
||||||
R_UNLESS(read_size == file_size, ldr::ResultInvalidNso());
|
R_UNLESS_LOG(read_size == file_size, ldr::ResultInvalidNso(), "[ldr] Couldn't read segment from file!\n");
|
||||||
|
|
||||||
/* Uncompress if necessary. */
|
/* Uncompress if necessary. */
|
||||||
R_SUCCEED_IF(!is_compressed);
|
R_SUCCEED_IF(!is_compressed);
|
||||||
|
|
||||||
auto compressed_data_buf = reinterpret_cast<const void *>(load_address);
|
auto compressed_data_buf = reinterpret_cast<const void *>(load_address);
|
||||||
|
|
||||||
if (is_zstd) {
|
if (is_zbic) {
|
||||||
bool decompressed = util::DecompressZstdForLoader(reinterpret_cast<void *>(g_zstd_dctx_workspace), ZstdDctxWorkspaceSize, reinterpret_cast<void *>(map_base), static_cast<size_t>(map_end - map_base), segment_size, compressed_data_buf, file_size);
|
bool decompressed = util::DecompressZstdWithBic(reinterpret_cast<void *>(g_zstd_dctx_workspace), sizeof(g_zstd_dctx_workspace), reinterpret_cast<void *>(map_base), static_cast<size_t>(map_end - map_base), segment_size, compressed_data_buf, file_size);
|
||||||
R_UNLESS(decompressed, ldr::ResultInvalidNso());
|
R_UNLESS_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with zbic!\n");
|
||||||
} else {
|
} else {
|
||||||
bool decompressed = (util::DecompressLZ4(reinterpret_cast<void *>(map_base), segment_size, compressed_data_buf, file_size) == static_cast<int>(segment_size));
|
bool decompressed = (util::DecompressLZ4(reinterpret_cast<void *>(map_base), segment_size, compressed_data_buf, file_size) == static_cast<int>(segment_size));
|
||||||
R_UNLESS(decompressed, ldr::ResultInvalidNso());
|
R_UNLESS_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with lz4!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@@ -675,12 +679,12 @@ namespace ams::ldr {
|
|||||||
crypto::GenerateSha256(hash, sizeof(hash),
|
crypto::GenerateSha256(hash, sizeof(hash),
|
||||||
reinterpret_cast<void *>(map_address + nso_header->segments[segment].dst_offset),
|
reinterpret_cast<void *>(map_address + nso_header->segments[segment].dst_offset),
|
||||||
nso_header->segments[segment].size);
|
nso_header->segments[segment].size);
|
||||||
R_UNLESS(std::memcmp(hash, nso_header->segment_hashes[segment], sizeof(hash)) == 0, ldr::ResultInvalidNso());
|
R_UNLESS_LOG(std::memcmp(hash, nso_header->segment_hashes[segment], sizeof(hash)) == 0, ldr::ResultInvalidNso(), "[ldr] Invalid segment hash!\n");
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoadAutoLoadModule(os::NativeHandle process_handle, fs::FileHandle file, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size, size_t map_size) {
|
Result LoadAutoLoadModule(os::NativeHandle process_handle, fs::FileHandle file, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size, size_t map_size) {
|
||||||
const bool is_zstd = (nso_header->flags & NsoHeader::Flag_UseZbicCompression) != 0;
|
const bool is_zbic = (nso_header->flags & NsoHeader::Flag_UseZbicCompression) != 0;
|
||||||
|
|
||||||
/* Map and read data from file. */
|
/* Map and read data from file. */
|
||||||
{
|
{
|
||||||
@@ -694,11 +698,11 @@ namespace ams::ldr {
|
|||||||
|
|
||||||
/* Load NSO segments. */
|
/* Load NSO segments. */
|
||||||
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Text].file_offset, nso_header->text_compressed_size, nso_header->text_size,
|
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Text].file_offset, nso_header->text_compressed_size, nso_header->text_size,
|
||||||
(nso_header->flags & NsoHeader::Flag_CompressedText) != 0, is_zstd, map_address + nso_header->text_dst_offset, map_end));
|
(nso_header->flags & NsoHeader::Flag_CompressedText) != 0, is_zbic, map_address + nso_header->text_dst_offset, map_end));
|
||||||
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Ro].file_offset, nso_header->ro_compressed_size, nso_header->ro_size,
|
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Ro].file_offset, nso_header->ro_compressed_size, nso_header->ro_size,
|
||||||
(nso_header->flags & NsoHeader::Flag_CompressedRo) != 0, is_zstd, map_address + nso_header->ro_dst_offset, map_end));
|
(nso_header->flags & NsoHeader::Flag_CompressedRo) != 0, is_zbic, map_address + nso_header->ro_dst_offset, map_end));
|
||||||
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Rw].file_offset, nso_header->rw_compressed_size, nso_header->rw_size,
|
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Rw].file_offset, nso_header->rw_compressed_size, nso_header->rw_size,
|
||||||
(nso_header->flags & NsoHeader::Flag_CompressedRw) != 0, is_zstd, map_address + nso_header->rw_dst_offset, map_end));
|
(nso_header->flags & NsoHeader::Flag_CompressedRw) != 0, is_zbic, map_address + nso_header->rw_dst_offset, map_end));
|
||||||
|
|
||||||
/* Clear unused space to zero. */
|
/* Clear unused space to zero. */
|
||||||
const size_t text_end = static_cast<size_t>(nso_header->text_dst_offset) + static_cast<size_t>(nso_header->text_size);
|
const size_t text_end = static_cast<size_t>(nso_header->text_dst_offset) + static_cast<size_t>(nso_header->text_size);
|
||||||
@@ -744,14 +748,15 @@ namespace ams::ldr {
|
|||||||
|
|
||||||
for (int i = 0; i < ctx.nso_count; i++) {
|
for (int i = 0; i < ctx.nso_count; i++) {
|
||||||
const NsoIndex nso_idx = static_cast<NsoIndex>(ctx.ali.nso_indices[i]);
|
const NsoIndex nso_idx = static_cast<NsoIndex>(ctx.ali.nso_indices[i]);
|
||||||
|
const bool is_zbic = (ctx.headers[i].flags & NsoHeader::Flag_UseZbicCompression) != 0;
|
||||||
|
const size_t map_size = is_zbic ? (total_end - process_info->nso_address[i]) : process_info->nso_size[i];
|
||||||
|
|
||||||
|
AMS_LOG("[ldr] module[%d]: idx=%d, path='%s', zbic=%d\n", i, (int)nso_idx, GetNsoPath(nso_idx), is_zbic);
|
||||||
|
|
||||||
fs::FileHandle file;
|
fs::FileHandle file;
|
||||||
R_TRY(fs::OpenFile(std::addressof(file), GetNsoPath(nso_idx), fs::OpenMode_Read));
|
R_TRY(fs::OpenFile(std::addressof(file), GetNsoPath(nso_idx), fs::OpenMode_Read));
|
||||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||||
|
|
||||||
const bool is_zstd = (ctx.headers[i].flags & NsoHeader::Flag_UseZbicCompression) != 0;
|
|
||||||
const size_t map_size = is_zstd ? (total_end - process_info->nso_address[i]) : process_info->nso_size[i];
|
|
||||||
|
|
||||||
R_TRY(LoadAutoLoadModule(process_info->process_handle, file, ctx.headers + i,
|
R_TRY(LoadAutoLoadModule(process_info->process_handle, file, ctx.headers + i,
|
||||||
process_info->nso_address[i], process_info->nso_size[i], map_size));
|
process_info->nso_address[i], process_info->nso_size[i], map_size));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define AMS_ZSTD_IMPLEMENTATION
|
|
||||||
#include <stratosphere/util/util_zbic_for_loader.hpp>
|
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
"filesystem_access": {
|
"filesystem_access": {
|
||||||
"permissions": "0xFFFFFFFFFFFFFFFF"
|
"permissions": "0xFFFFFFFFFFFFFFFF"
|
||||||
},
|
},
|
||||||
"service_access": ["erpt:c", "fatal:u", "fsp-srv", "ldr:shel", "lm", "lr", "pm:shell", "set", "set:sys"],
|
"service_access": ["fatal:u", "fsp-srv", "ldr:shel", "lr", "pm:shell", "set:sys"],
|
||||||
"service_host": ["pgl"],
|
"service_host": ["pgl"],
|
||||||
"kernel_capabilities": [{
|
"kernel_capabilities": [{
|
||||||
"type": "kernel_flags",
|
"type": "kernel_flags",
|
||||||
@@ -87,4 +87,4 @@
|
|||||||
"type": "handle_table_size",
|
"type": "handle_table_size",
|
||||||
"value": 256
|
"value": 256
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,13 +30,14 @@ namespace ams {
|
|||||||
fs::InitializeForSystem();
|
fs::InitializeForSystem();
|
||||||
fs::SetAllocator(pgl::srv::Allocate, pgl::srv::Deallocate);
|
fs::SetAllocator(pgl::srv::Allocate, pgl::srv::Deallocate);
|
||||||
fs::SetEnabledAutoAbort(false);
|
fs::SetEnabledAutoAbort(false);
|
||||||
|
|
||||||
|
/* Initialize lr. */
|
||||||
|
lr::Initialize();
|
||||||
|
|
||||||
/* Initialize other services we need. */
|
/* Initialize other services we need. */
|
||||||
R_ABORT_UNLESS(setInitialize());
|
|
||||||
R_ABORT_UNLESS(setsysInitialize());
|
R_ABORT_UNLESS(setsysInitialize());
|
||||||
R_ABORT_UNLESS(pmshellInitialize());
|
R_ABORT_UNLESS(pmshellInitialize());
|
||||||
R_ABORT_UNLESS(ldrShellInitialize());
|
R_ABORT_UNLESS(ldrShellInitialize());
|
||||||
R_ABORT_UNLESS(lrInitialize());
|
|
||||||
|
|
||||||
/* Verify that we can sanely execute. */
|
/* Verify that we can sanely execute. */
|
||||||
ams::CheckApiVersion();
|
ams::CheckApiVersion();
|
||||||
@@ -58,3 +59,36 @@ namespace ams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Override operator new. */
|
||||||
|
void *operator new(size_t size) {
|
||||||
|
return ams::pgl::srv::Allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *operator new(size_t size, const std::nothrow_t &) {
|
||||||
|
return ams::pgl::srv::Allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete(void *p) {
|
||||||
|
return ams::pgl::srv::Deallocate(p, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete(void *p, size_t size) {
|
||||||
|
return ams::pgl::srv::Deallocate(p, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *operator new[](size_t size) {
|
||||||
|
return ams::pgl::srv::Allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *operator new[](size_t size, const std::nothrow_t &) {
|
||||||
|
return ams::pgl::srv::Allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void *p) {
|
||||||
|
return ams::pgl::srv::Deallocate(p, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete[](void *p, size_t size) {
|
||||||
|
return ams::pgl::srv::Deallocate(p, size);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user