Compare commits
96 Commits
1.3.0
...
1.4.0-rele
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36a33617a4 | ||
|
|
8ce4f19615 | ||
|
|
05fee5d53c | ||
|
|
f88606fbc1 | ||
|
|
e580c3970c | ||
|
|
2603136e8b | ||
|
|
3d3f8629af | ||
|
|
d178ea368a | ||
|
|
b444385762 | ||
|
|
0c3f1bed33 | ||
|
|
bf4fdf6188 | ||
|
|
13238fc4fd | ||
|
|
e7a1e0fee2 | ||
|
|
5a918f3bc9 | ||
|
|
ea82889e6c | ||
|
|
7f2cbba543 | ||
|
|
5ee7d8a5ed | ||
|
|
947fdcf6f6 | ||
|
|
2e73f33eb0 | ||
|
|
752704a798 | ||
|
|
d00406e089 | ||
|
|
dddb5bfdea | ||
|
|
ed0572bd53 | ||
|
|
b3bbc99cfb | ||
|
|
0ebbbc839f | ||
|
|
275c0234cb | ||
|
|
427130a122 | ||
|
|
ef07964ea0 | ||
|
|
e1aff401ba | ||
|
|
05de5538d6 | ||
|
|
9929517a83 | ||
|
|
545765d167 | ||
|
|
8d9e3f2a31 | ||
|
|
28f0940c58 | ||
|
|
d954e85826 | ||
|
|
7e6b369605 | ||
|
|
e702eab21c | ||
|
|
592b9c66d1 | ||
|
|
8e17feff94 | ||
|
|
6514e365ad | ||
|
|
efa4a346af | ||
|
|
d75f9bbedf | ||
|
|
ea7f51a279 | ||
|
|
a65b6df8d2 | ||
|
|
4e112de223 | ||
|
|
20d200471d | ||
|
|
5f2d713fe4 | ||
|
|
114d2598da | ||
|
|
36bdb83cfc | ||
|
|
a975689c59 | ||
|
|
a809e23320 | ||
|
|
4db485083b | ||
|
|
e96972c939 | ||
|
|
3545c0aac2 | ||
|
|
d85875b910 | ||
|
|
b1367942a2 | ||
|
|
c2c0a2e169 | ||
|
|
f5052b4bca | ||
|
|
70d67bb115 | ||
|
|
9056e0b05f | ||
|
|
895b6d0470 | ||
|
|
dfba595cdc | ||
|
|
175a34da43 | ||
|
|
02b126c2be | ||
|
|
b45671fd35 | ||
|
|
106599895d | ||
|
|
80154b0a54 | ||
|
|
62eb4d6989 | ||
|
|
b52e44e798 | ||
|
|
72baa4ff18 | ||
|
|
442656899f | ||
|
|
d7f89a0c31 | ||
|
|
2e6223d9d0 | ||
|
|
28f11a86fd | ||
|
|
a8b52dc123 | ||
|
|
9b47ddf01f | ||
|
|
0fbf007bcf | ||
|
|
4ad8dad416 | ||
|
|
8e258bde9d | ||
|
|
c0d5140ef0 | ||
|
|
1bef1b58d4 | ||
|
|
07cd682460 | ||
|
|
e5c3d264ec | ||
|
|
bbf22b4c60 | ||
|
|
dd78ede99f | ||
|
|
e5b1739f65 | ||
|
|
a4a2cc2218 | ||
|
|
5ffbed1bee | ||
|
|
ec44eaa263 | ||
|
|
20e53fcd82 | ||
|
|
64c6ef2de7 | ||
|
|
817ad8f98d | ||
|
|
dfa475a769 | ||
|
|
141ae5c7ab | ||
|
|
4646581e93 | ||
|
|
b69fa13576 |
@@ -1,4 +1,32 @@
|
||||
# Changelog
|
||||
## 1.4.0
|
||||
+ Support was added for 15.0.0.
|
||||
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||
+ `ncm` was updated to reflect the latest official kernel behavior.
|
||||
+ A number of minor issues were fixed and improvements were made, including:
|
||||
+ The capacity limit on registered add-on contents was fixed in NCM to reflect the increase that occurred in 12.0.0.
|
||||
+ An off-by-one was fixed in mesosphere when computing the new value for an address arbiter signaled with ModifyByWaitingCountIfEqual.
|
||||
+ dmnt.gen2's gdbstub now sanitizes thread names to prevent invalid characters from breaking gdb.
|
||||
+ dmnt.gen2's gdbstub now reports the architecture tag correctly when attached to 32-bit processes.
|
||||
+ Support for program-specific html manual content overrides was added for non-hbl takeover context.
|
||||
+ A bug was fixed in how emummc constructed the alternate Nintendo directory path.
|
||||
+ Previously, this was using `/*/Nintendo/Nintendo` instead of `/*/Nintendo`.
|
||||
+ Code was added to automatically move the old folders to the new ones when booting into emummc.
|
||||
+ A bug was fixed in boot that caused an incorrectly low input voltage limit to be set.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 1.3.2
|
||||
+ Support was improved for 14.0.0+.
|
||||
+ `loader` was updated to reflect the latest official behaviors.
|
||||
+ `ro` was updated to reflect the latest official behaviors.
|
||||
+ A number of minor issues were fixed and improvements were made, including:
|
||||
+ A memory leak was fixed in filesystem path management; this could cause a crash when launching games ~100 times, or when deleting/re-downloading games.
|
||||
+ A bug was fixed that could cause threads to not see a newly signaled semaphore.
|
||||
+ A number of minor inaccuracies were fixed in the updated FileSystem APIs.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 1.3.1
|
||||
+ Support was added for 14.1.0.
|
||||
+ A number of minor under the hood improvements to accuracy were made to better reflect latest official system module behavior, particularly around FS apis.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 1.3.0
|
||||
+ Support was added for 14.0.0.
|
||||
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||
|
||||
4
emummc/.gitrepo
vendored
4
emummc/.gitrepo
vendored
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/m4xw/emummc
|
||||
branch = develop
|
||||
commit = 56a2e8a2078944d9bf8daead237036254bb6e36d
|
||||
parent = 4f763b2aa401ac3e3d699ec8c866ae9b3c8fb28d
|
||||
commit = 4714b2df9eaf68fb85516b35f7f4265ab0413825
|
||||
parent = 99f6a96845b6097d50f5059eea9245d27876f26a
|
||||
method = merge
|
||||
cmdver = 0.4.1
|
||||
|
||||
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***
|
||||
|
||||
### Supported Horizon Versions
|
||||
**1.0.0 - 13.1.0**
|
||||
**1.0.0 - 15.0.0**
|
||||
|
||||
## Features
|
||||
* Arbitrary SDMMC backend selection
|
||||
|
||||
8
emummc/source/FS/FS_offsets.c
vendored
8
emummc/source/FS/FS_offsets.c
vendored
@@ -61,6 +61,8 @@
|
||||
#include "offsets/1310_exfat.h"
|
||||
#include "offsets/1400.h"
|
||||
#include "offsets/1400_exfat.h"
|
||||
#include "offsets/1500.h"
|
||||
#include "offsets/1500_exfat.h"
|
||||
#include "../utils/fatal.h"
|
||||
|
||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
||||
@@ -133,6 +135,8 @@ DEFINE_OFFSET_STRUCT(_1310);
|
||||
DEFINE_OFFSET_STRUCT(_1310_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1400);
|
||||
DEFINE_OFFSET_STRUCT(_1400_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1500);
|
||||
DEFINE_OFFSET_STRUCT(_1500_EXFAT);
|
||||
|
||||
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
switch (version) {
|
||||
@@ -226,6 +230,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1400));
|
||||
case FS_VER_14_0_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1400_EXFAT));
|
||||
case FS_VER_15_0_0:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1500));
|
||||
case FS_VER_15_0_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1500_EXFAT));
|
||||
default:
|
||||
fatal_abort(Fatal_UnknownVersion);
|
||||
}
|
||||
|
||||
3
emummc/source/FS/FS_versions.h
vendored
3
emummc/source/FS/FS_versions.h
vendored
@@ -89,6 +89,9 @@ enum FS_VER
|
||||
FS_VER_14_0_0,
|
||||
FS_VER_14_0_0_EXFAT,
|
||||
|
||||
FS_VER_15_0_0,
|
||||
FS_VER_15_0_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
};
|
||||
|
||||
|
||||
59
emummc/source/FS/offsets/1500.h
vendored
Normal file
59
emummc/source/FS/offsets/1500.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_1500_H__
|
||||
#define __FS_1500_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1500_SDMMC_ACCESSOR_GC 0x183E20
|
||||
#define FS_OFFSET_1500_SDMMC_ACCESSOR_SD 0x185AA0
|
||||
#define FS_OFFSET_1500_SDMMC_ACCESSOR_NAND 0x1842E0
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1500_SDMMC_WRAPPER_READ 0x17FCF0
|
||||
#define FS_OFFSET_1500_SDMMC_WRAPPER_WRITE 0x17FD50
|
||||
#define FS_OFFSET_1500_RTLD 0x26518
|
||||
#define FS_OFFSET_1500_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||
|
||||
#define FS_OFFSET_1500_CLKRST_SET_MIN_V_CLK_RATE 0x1A0870
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1500_LOCK_MUTEX 0x1791A0
|
||||
#define FS_OFFSET_1500_UNLOCK_MUTEX 0x1791F0
|
||||
|
||||
#define FS_OFFSET_1500_SDMMC_WRAPPER_CONTROLLER_OPEN 0x17FCB0
|
||||
#define FS_OFFSET_1500_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x17FCD0
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1500_SD_MUTEX 0xFF33F0
|
||||
#define FS_OFFSET_1500_NAND_MUTEX 0xFEE2E8
|
||||
#define FS_OFFSET_1500_ACTIVE_PARTITION 0xFEE328
|
||||
#define FS_OFFSET_1500_SDMMC_DAS_HANDLE 0xFD38D8
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1500_SD_DAS_INIT 0x25454
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1500_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00063050, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006FDE8, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x000768D4, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00089364, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1500_H__
|
||||
59
emummc/source/FS/offsets/1500_exfat.h
vendored
Normal file
59
emummc/source/FS/offsets/1500_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_1500_EXFAT_H__
|
||||
#define __FS_1500_EXFAT_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1500_EXFAT_SDMMC_ACCESSOR_GC 0x18EDB0
|
||||
#define FS_OFFSET_1500_EXFAT_SDMMC_ACCESSOR_SD 0x190A30
|
||||
#define FS_OFFSET_1500_EXFAT_SDMMC_ACCESSOR_NAND 0x18F270
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1500_EXFAT_SDMMC_WRAPPER_READ 0x18AC80
|
||||
#define FS_OFFSET_1500_EXFAT_SDMMC_WRAPPER_WRITE 0x18ACE0
|
||||
#define FS_OFFSET_1500_EXFAT_RTLD 0x26518
|
||||
#define FS_OFFSET_1500_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||
|
||||
#define FS_OFFSET_1500_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1AB800
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1500_EXFAT_LOCK_MUTEX 0x184130
|
||||
#define FS_OFFSET_1500_EXFAT_UNLOCK_MUTEX 0x184180
|
||||
|
||||
#define FS_OFFSET_1500_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x18AC40
|
||||
#define FS_OFFSET_1500_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x18AC60
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1500_EXFAT_SD_MUTEX 0x10053F0
|
||||
#define FS_OFFSET_1500_EXFAT_NAND_MUTEX 0x10002E8
|
||||
#define FS_OFFSET_1500_EXFAT_ACTIVE_PARTITION 0x1000328
|
||||
#define FS_OFFSET_1500_EXFAT_SDMMC_DAS_HANDLE 0xFE08D8
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1500_EXFAT_SD_DAS_INIT 0x25454
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1500_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00063050, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006FDE8, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x000768D4, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00089364, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1500_EXFAT_H__
|
||||
@@ -62,7 +62,7 @@ namespace ams::secmon::fatal {
|
||||
/* Write the context to the file. */
|
||||
R_TRY(fs::WriteFile(file, 0, ctx, sizeof(*ctx), fs::WriteOption::Flush));
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,11 +48,11 @@ namespace ams::secmon::fatal {
|
||||
//sdmmc::Deactivate(Port);
|
||||
R_TRY(sdmmc::Activate(Port));
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw) {
|
||||
return sdmmc::CheckSdCardConnection(out_sm, out_bw, Port);
|
||||
R_RETURN(sdmmc::CheckSdCardConnection(out_sm, out_bw, Port));
|
||||
}
|
||||
|
||||
Result ReadSdCard(void *dst, size_t size, size_t sector_index, size_t sector_count) {
|
||||
@@ -78,7 +78,7 @@ namespace ams::secmon::fatal {
|
||||
sector_count -= cur_sectors;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result WriteSdCard(size_t sector_index, size_t sector_count, const void *src, size_t size) {
|
||||
@@ -104,7 +104,7 @@ namespace ams::secmon::fatal {
|
||||
sector_count -= cur_sectors;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,45 +34,45 @@ namespace ams::fs {
|
||||
Result TranslateFatFsError(FRESULT res) {
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
case FR_DISK_ERR:
|
||||
return fs::ResultMmcAccessFailed();
|
||||
R_THROW(fs::ResultMmcAccessFailed());
|
||||
case FR_INT_ERR:
|
||||
return fs::ResultPreconditionViolation();
|
||||
R_THROW(fs::ResultPreconditionViolation());
|
||||
case FR_NOT_READY:
|
||||
return fs::ResultMmcAccessFailed();
|
||||
R_THROW(fs::ResultMmcAccessFailed());
|
||||
case FR_NO_FILE:
|
||||
return fs::ResultPathNotFound();
|
||||
R_THROW(fs::ResultPathNotFound());
|
||||
case FR_NO_PATH:
|
||||
return fs::ResultPathNotFound();
|
||||
R_THROW(fs::ResultPathNotFound());
|
||||
case FR_INVALID_NAME:
|
||||
return fs::ResultInvalidPath();
|
||||
R_THROW(fs::ResultInvalidPath());
|
||||
case FR_DENIED:
|
||||
return fs::ResultPermissionDenied();
|
||||
R_THROW(fs::ResultPermissionDenied());
|
||||
case FR_EXIST:
|
||||
return fs::ResultPathAlreadyExists();
|
||||
R_THROW(fs::ResultPathAlreadyExists());
|
||||
case FR_INVALID_OBJECT:
|
||||
return fs::ResultInvalidArgument();
|
||||
R_THROW(fs::ResultInvalidArgument());
|
||||
case FR_WRITE_PROTECTED:
|
||||
return fs::ResultWriteNotPermitted();
|
||||
R_THROW(fs::ResultWriteNotPermitted());
|
||||
case FR_INVALID_DRIVE:
|
||||
return fs::ResultInvalidMountName();
|
||||
R_THROW(fs::ResultInvalidMountName());
|
||||
case FR_NOT_ENABLED:
|
||||
return fs::ResultInvalidMountName(); /* BAD/TODO */
|
||||
R_THROW(fs::ResultInvalidMountName()); /* BAD/TODO */
|
||||
case FR_NO_FILESYSTEM:
|
||||
return fs::ResultInvalidMountName(); /* BAD/TODO */
|
||||
R_THROW(fs::ResultInvalidMountName()); /* BAD/TODO */
|
||||
case FR_TIMEOUT:
|
||||
return fs::ResultTargetLocked(); /* BAD/TODO */
|
||||
R_THROW(fs::ResultTargetLocked()); /* BAD/TODO */
|
||||
case FR_LOCKED:
|
||||
return fs::ResultTargetLocked();
|
||||
R_THROW(fs::ResultTargetLocked());
|
||||
case FR_NOT_ENOUGH_CORE:
|
||||
return fs::ResultPreconditionViolation(); /* BAD/TODO */
|
||||
R_THROW(fs::ResultPreconditionViolation()); /* BAD/TODO */
|
||||
case FR_TOO_MANY_OPEN_FILES:
|
||||
return fs::ResultPreconditionViolation(); /* BAD/TODO */
|
||||
R_THROW(fs::ResultPreconditionViolation()); /* BAD/TODO */
|
||||
case FR_INVALID_PARAMETER:
|
||||
return fs::ResultInvalidArgument();
|
||||
R_THROW(fs::ResultInvalidArgument());
|
||||
default:
|
||||
return fs::ResultInternal();
|
||||
R_THROW(fs::ResultInternal());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,11 +125,11 @@ namespace ams::fs {
|
||||
/* Expand the file. */
|
||||
R_TRY(TranslateFatFsError(f_expand(std::addressof(fp), size, 1)));
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CreateDirectory(const char *path) {
|
||||
return TranslateFatFsError(f_mkdir(path));
|
||||
R_RETURN(TranslateFatFsError(f_mkdir(path)));
|
||||
}
|
||||
|
||||
Result OpenFile(FileHandle *out_file, const char *path, int mode) {
|
||||
@@ -144,10 +144,10 @@ namespace ams::fs {
|
||||
out_file->_handle = fp;
|
||||
g_files_opened[i] = true;
|
||||
g_open_modes[i] = mode;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
return fs::ResultOpenCountLimit();
|
||||
R_THROW(fs::ResultOpenCountLimit());
|
||||
}
|
||||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
|
||||
@@ -164,11 +164,11 @@ namespace ams::fs {
|
||||
/* Check that we read the correct amount. */
|
||||
R_UNLESS(br == size, fs::ResultOutOfRange());
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size) {
|
||||
return ReadFile(handle, offset, buffer, size, fs::ReadOption::None);
|
||||
R_RETURN(ReadFile(handle, offset, buffer, size, fs::ReadOption::None));
|
||||
}
|
||||
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
|
||||
@@ -185,21 +185,21 @@ namespace ams::fs {
|
||||
/* Set the output size. */
|
||||
*out = br;
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size) {
|
||||
return ReadFile(out, handle, offset, buffer, size, fs::ReadOption::None);
|
||||
R_RETURN(ReadFile(out, handle, offset, buffer, size, fs::ReadOption::None));
|
||||
}
|
||||
|
||||
Result GetFileSize(s64 *out, FileHandle handle) {
|
||||
FIL *fp = GetInternalFile(handle);
|
||||
*out = f_size(fp);
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result FlushFile(FileHandle handle) {
|
||||
return TranslateFatFsError(f_sync(GetInternalFile(handle)));
|
||||
R_RETURN(TranslateFatFsError(f_sync(GetInternalFile(handle))));
|
||||
}
|
||||
|
||||
Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) {
|
||||
@@ -218,7 +218,7 @@ namespace ams::fs {
|
||||
R_TRY(FlushFile(handle));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetFileSize(FileHandle handle, s64 size) {
|
||||
@@ -242,7 +242,7 @@ namespace ams::fs {
|
||||
/* Check that our expansion succeeded. */
|
||||
AMS_ASSERT(f_size(fp) == static_cast<FSIZE_t>(size));
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
int GetFileOpenMode(FileHandle handle) {
|
||||
|
||||
@@ -85,10 +85,10 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
/* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */
|
||||
/* TODO: Update on next change of keys. */
|
||||
/* Mariko Development Master Kek Source. */
|
||||
.byte 0xEC, 0x5E, 0xB5, 0x11, 0xD5, 0x43, 0x1E, 0x6A, 0x4E, 0x54, 0x6F, 0xD4, 0xD3, 0x22, 0xCE, 0x87
|
||||
.byte 0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7
|
||||
|
||||
/* Mariko Production Master Kek Source. */
|
||||
.byte 0xD2, 0x68, 0xC6, 0x53, 0x9D, 0x94, 0xF9, 0xA8, 0xA5, 0xA8, 0xA7, 0xC8, 0x8F, 0x53, 0x4B, 0x7A
|
||||
.byte 0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D
|
||||
|
||||
/* Development Master Key Vectors. */
|
||||
.byte 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE /* Zeroes encrypted with Master Key 00. */
|
||||
@@ -105,6 +105,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
.byte 0x21, 0x88, 0x6B, 0x10, 0x9E, 0x83, 0xD6, 0x52, 0xAB, 0x08, 0xDB, 0x6D, 0x39, 0xFF, 0x1C, 0x9C /* Master key 0A encrypted with Master key 0B. */
|
||||
.byte 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 /* Master key 0B encrypted with Master key 0C. */
|
||||
.byte 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 /* Master key 0C encrypted with Master key 0D. */
|
||||
.byte 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D /* Master key 0D encrypted with Master key 0E. */
|
||||
|
||||
/* Production Master Key Vectors. */
|
||||
.byte 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D /* Zeroes encrypted with Master Key 00. */
|
||||
@@ -121,6 +122,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
.byte 0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98 /* Master key 0A encrypted with Master key 0B. */
|
||||
.byte 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 /* Master key 0B encrypted with Master key 0C. */
|
||||
.byte 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 /* Master key 0C encrypted with Master key 0D. */
|
||||
.byte 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 /* Master key 0D encrypted with Master key 0E. */
|
||||
|
||||
/* Device Master Key Source Sources. */
|
||||
.byte 0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D /* 4.0.0 Device Master Key Source Source. */
|
||||
@@ -134,6 +136,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
.byte 0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6 /* 12.1.0 Device Master Key Source Source. */
|
||||
.byte 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F /* 13.0.0 Device Master Key Source Source. */
|
||||
.byte 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D /* 14.0.0 Device Master Key Source Source. */
|
||||
.byte 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 /* 15.0.0 Device Master Key Source Source. */
|
||||
|
||||
/* Development Device Master Kek Sources. */
|
||||
.byte 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 /* 4.0.0 Device Master Kek Source. */
|
||||
@@ -147,6 +150,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
.byte 0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB /* 12.1.0 Device Master Kek Source. */
|
||||
.byte 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F /* 13.0.0 Device Master Kek Source. */
|
||||
.byte 0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA /* 14.0.0 Device Master Kek Source. */
|
||||
.byte 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E /* 15.0.0 Device Master Kek Source. */
|
||||
|
||||
/* Production Device Master Kek Sources. */
|
||||
.byte 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D /* 4.0.0 Device Master Kek Source. */
|
||||
@@ -160,3 +164,4 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
.byte 0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3 /* 12.1.0 Device Master Kek Source. */
|
||||
.byte 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 /* 13.0.0 Device Master Kek Source. */
|
||||
.byte 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 /* 14.0.0 Device Master Kek Source. */
|
||||
.byte 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 /* 15.0.0 Device Master Kek Source. */
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace ams::secmon::boot {
|
||||
}
|
||||
|
||||
/* Check that the key generation is one that we can use. */
|
||||
static_assert(pkg1::KeyGeneration_Count == 14);
|
||||
static_assert(pkg1::KeyGeneration_Count == 15);
|
||||
if (key_generation >= pkg1::KeyGeneration_Count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace ams::secmon::smc {
|
||||
[fuse::DramId_IcosaSamsung6GB] = pkg1::MemorySize_6GB,
|
||||
[fuse::DramId_HoagHynix1y4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_AulaHynix1y4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaX1X2Samsung4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_Deprecated7] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSansung4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung8GB] = pkg1::MemorySize_8GB,
|
||||
[fuse::DramId_IowaHynix4GB] = pkg1::MemorySize_4GB,
|
||||
@@ -61,7 +61,7 @@ namespace ams::secmon::smc {
|
||||
[fuse::DramId_HoagSamsung8GB] = pkg1::MemorySize_8GB,
|
||||
[fuse::DramId_HoagHynix4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_HoagMicron4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung4GBY] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_Deprecated16] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung1y4GBX] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung1y8GBX] = pkg1::MemorySize_8GB,
|
||||
[fuse::DramId_HoagSamsung1y4GBX] = pkg1::MemorySize_4GB,
|
||||
@@ -74,6 +74,12 @@ namespace ams::secmon::smc {
|
||||
[fuse::DramId_HoagMicron1y4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_AulaMicron1y4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_AulaSamsung1y8GBX] = pkg1::MemorySize_8GB,
|
||||
[fuse::DramId_IowaX1X2Samsung4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_HoagX1X2Samsung4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_AulaX1X2Samsung4GB] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_IowaSamsung4GBY] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_HoagSamsung4GBY] = pkg1::MemorySize_4GB,
|
||||
[fuse::DramId_AulaSamsung4GBY] = pkg1::MemorySize_4GB,
|
||||
};
|
||||
|
||||
constexpr const pkg1::MemoryMode MemoryModes[] = {
|
||||
|
||||
@@ -39,45 +39,45 @@ namespace ams::fs {
|
||||
Result TranslateFatFsError(FRESULT res) {
|
||||
switch (res) {
|
||||
case FR_OK:
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
case FR_DISK_ERR:
|
||||
return fs::ResultMmcAccessFailed();
|
||||
R_THROW(fs::ResultMmcAccessFailed());
|
||||
case FR_INT_ERR:
|
||||
return fs::ResultPreconditionViolation();
|
||||
R_THROW(fs::ResultPreconditionViolation());
|
||||
case FR_NOT_READY:
|
||||
return fs::ResultMmcAccessFailed();
|
||||
R_THROW(fs::ResultMmcAccessFailed());
|
||||
case FR_NO_FILE:
|
||||
return fs::ResultPathNotFound();
|
||||
R_THROW(fs::ResultPathNotFound());
|
||||
case FR_NO_PATH:
|
||||
return fs::ResultPathNotFound();
|
||||
R_THROW(fs::ResultPathNotFound());
|
||||
case FR_INVALID_NAME:
|
||||
return fs::ResultInvalidPath();
|
||||
R_THROW(fs::ResultInvalidPath());
|
||||
case FR_DENIED:
|
||||
return fs::ResultPermissionDenied();
|
||||
R_THROW(fs::ResultPermissionDenied());
|
||||
case FR_EXIST:
|
||||
return fs::ResultPathAlreadyExists();
|
||||
R_THROW(fs::ResultPathAlreadyExists());
|
||||
case FR_INVALID_OBJECT:
|
||||
return fs::ResultInvalidArgument();
|
||||
R_THROW(fs::ResultInvalidArgument());
|
||||
case FR_WRITE_PROTECTED:
|
||||
return fs::ResultWriteNotPermitted();
|
||||
R_THROW(fs::ResultWriteNotPermitted());
|
||||
case FR_INVALID_DRIVE:
|
||||
return fs::ResultInvalidMountName();
|
||||
R_THROW(fs::ResultInvalidMountName());
|
||||
case FR_NOT_ENABLED:
|
||||
return fs::ResultInvalidMountName(); /* BAD/TODO */
|
||||
R_THROW(fs::ResultInvalidMountName()); /* BAD/TODO */
|
||||
case FR_NO_FILESYSTEM:
|
||||
return fs::ResultInvalidMountName(); /* BAD/TODO */
|
||||
R_THROW(fs::ResultInvalidMountName()); /* BAD/TODO */
|
||||
case FR_TIMEOUT:
|
||||
return fs::ResultTargetLocked(); /* BAD/TODO */
|
||||
R_THROW(fs::ResultTargetLocked()); /* BAD/TODO */
|
||||
case FR_LOCKED:
|
||||
return fs::ResultTargetLocked();
|
||||
R_THROW(fs::ResultTargetLocked());
|
||||
case FR_NOT_ENOUGH_CORE:
|
||||
return fs::ResultPreconditionViolation(); /* BAD/TODO */
|
||||
R_THROW(fs::ResultPreconditionViolation()); /* BAD/TODO */
|
||||
case FR_TOO_MANY_OPEN_FILES:
|
||||
return fs::ResultPreconditionViolation(); /* BAD/TODO */
|
||||
R_THROW(fs::ResultPreconditionViolation()); /* BAD/TODO */
|
||||
case FR_INVALID_PARAMETER:
|
||||
return fs::ResultInvalidArgument();
|
||||
R_THROW(fs::ResultInvalidArgument());
|
||||
default:
|
||||
return fs::ResultInternal();
|
||||
R_THROW(fs::ResultInternal());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace ams::fs {
|
||||
*out_entry_type = (info.fattrib & AM_DIR) ? DirectoryEntryType_Directory : DirectoryEntryType_File;
|
||||
*out_archive = (info.fattrib & AM_ARC);
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CreateFile(const char *path, s64 size) {
|
||||
@@ -152,11 +152,11 @@ namespace ams::fs {
|
||||
/* Expand the file. */
|
||||
R_TRY(TranslateFatFsError(f_expand(std::addressof(fp), size, 1)));
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CreateDirectory(const char *path) {
|
||||
return TranslateFatFsError(f_mkdir(path));
|
||||
R_RETURN(TranslateFatFsError(f_mkdir(path)));
|
||||
}
|
||||
|
||||
Result OpenFile(FileHandle *out_file, const char *path, int mode) {
|
||||
@@ -171,10 +171,10 @@ namespace ams::fs {
|
||||
out_file->_handle = fp;
|
||||
g_files_opened[i] = true;
|
||||
g_open_modes[i] = mode;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
return fs::ResultOpenCountLimit();
|
||||
R_THROW(fs::ResultOpenCountLimit());
|
||||
}
|
||||
|
||||
Result OpenDirectory(DirectoryHandle *out_dir, const char *path) {
|
||||
@@ -188,10 +188,10 @@ namespace ams::fs {
|
||||
/* Set the output. */
|
||||
out_dir->_handle = dp;
|
||||
g_dirs_opened[i] = true;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
}
|
||||
return fs::ResultOpenCountLimit();
|
||||
R_THROW(fs::ResultOpenCountLimit());
|
||||
}
|
||||
|
||||
Result ReadDirectory(s64 *out_count, DirectoryEntry *out_entries, DirectoryHandle handle, s64 max_entries) {
|
||||
@@ -209,7 +209,7 @@ namespace ams::fs {
|
||||
}
|
||||
|
||||
*out_count = count;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void CloseDirectory(DirectoryHandle handle) {
|
||||
@@ -232,11 +232,11 @@ namespace ams::fs {
|
||||
/* Check that we read the correct amount. */
|
||||
R_UNLESS(br == size, fs::ResultOutOfRange());
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size) {
|
||||
return ReadFile(handle, offset, buffer, size, fs::ReadOption::None);
|
||||
R_RETURN(ReadFile(handle, offset, buffer, size, fs::ReadOption::None));
|
||||
}
|
||||
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
|
||||
@@ -253,21 +253,21 @@ namespace ams::fs {
|
||||
/* Set the output size. */
|
||||
*out = br;
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size) {
|
||||
return ReadFile(out, handle, offset, buffer, size, fs::ReadOption::None);
|
||||
R_RETURN(ReadFile(out, handle, offset, buffer, size, fs::ReadOption::None));
|
||||
}
|
||||
|
||||
Result GetFileSize(s64 *out, FileHandle handle) {
|
||||
FIL *fp = GetInternalFile(handle);
|
||||
*out = f_size(fp);
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result FlushFile(FileHandle handle) {
|
||||
return TranslateFatFsError(f_sync(GetInternalFile(handle)));
|
||||
R_RETURN(TranslateFatFsError(f_sync(GetInternalFile(handle))));
|
||||
}
|
||||
|
||||
Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) {
|
||||
@@ -286,7 +286,7 @@ namespace ams::fs {
|
||||
R_TRY(FlushFile(handle));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetFileSize(FileHandle handle, s64 size) {
|
||||
@@ -310,7 +310,7 @@ namespace ams::fs {
|
||||
/* Check that our expansion succeeded. */
|
||||
AMS_ASSERT(f_size(fp) == static_cast<FSIZE_t>(size));
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
int GetFileOpenMode(FileHandle handle) {
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace ams::fs {
|
||||
|
||||
Result FileHandleStorage::UpdateSize() {
|
||||
R_SUCCEED_IF(m_size != InvalidSize);
|
||||
return GetFileSize(std::addressof(m_size), m_handle);
|
||||
R_RETURN(GetFileSize(std::addressof(m_size), m_handle));
|
||||
}
|
||||
|
||||
Result FileHandleStorage::Read(s64 offset, void *buffer, size_t size) {
|
||||
@@ -34,9 +34,9 @@ namespace ams::fs {
|
||||
R_TRY(this->UpdateSize());
|
||||
|
||||
/* Ensure our access is valid. */
|
||||
R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange());
|
||||
R_TRY(IStorage::CheckAccessRange(offset, size, m_size));
|
||||
|
||||
return ReadFile(m_handle, offset, buffer, size, fs::ReadOption());
|
||||
R_RETURN(ReadFile(m_handle, offset, buffer, size, fs::ReadOption()));
|
||||
}
|
||||
|
||||
Result FileHandleStorage::Write(s64 offset, const void *buffer, size_t size) {
|
||||
@@ -50,24 +50,24 @@ namespace ams::fs {
|
||||
R_TRY(this->UpdateSize());
|
||||
|
||||
/* Ensure our access is valid. */
|
||||
R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange());
|
||||
R_TRY(IStorage::CheckAccessRange(offset, size, m_size));
|
||||
|
||||
return WriteFile(m_handle, offset, buffer, size, fs::WriteOption());
|
||||
R_RETURN(WriteFile(m_handle, offset, buffer, size, fs::WriteOption()));
|
||||
}
|
||||
|
||||
Result FileHandleStorage::Flush() {
|
||||
return FlushFile(m_handle);
|
||||
R_RETURN(FlushFile(m_handle));
|
||||
}
|
||||
|
||||
Result FileHandleStorage::GetSize(s64 *out_size) {
|
||||
R_TRY(this->UpdateSize());
|
||||
*out_size = m_size;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result FileHandleStorage::SetSize(s64 size) {
|
||||
m_size = InvalidSize;
|
||||
return SetFileSize(m_handle, size);
|
||||
R_RETURN(SetFileSize(m_handle, size));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,25 +31,38 @@ namespace ams::fs {
|
||||
|
||||
virtual Result GetSize(s64 *out) = 0;
|
||||
public:
|
||||
static inline bool CheckAccessRange(s64 offset, s64 size, s64 total_size) {
|
||||
return offset >= 0 &&
|
||||
size >= 0 &&
|
||||
size <= total_size &&
|
||||
offset <= (total_size - size);
|
||||
static inline Result CheckAccessRange(s64 offset, s64 size, s64 total_size) {
|
||||
R_UNLESS(offset >= 0, fs::ResultInvalidOffset());
|
||||
R_UNLESS(size >= 0, fs::ResultInvalidSize());
|
||||
R_UNLESS(util::CanAddWithoutOverflow<s64>(offset, size), fs::ResultOutOfRange());
|
||||
R_UNLESS(offset + size <= total_size, fs::ResultOutOfRange());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
static inline bool CheckAccessRange(s64 offset, size_t size, s64 total_size) {
|
||||
return CheckAccessRange(offset, static_cast<s64>(size), total_size);
|
||||
static ALWAYS_INLINE Result CheckAccessRange(s64 offset, size_t size, s64 total_size) {
|
||||
R_RETURN(CheckAccessRange(offset, static_cast<s64>(size), total_size));
|
||||
}
|
||||
|
||||
static inline bool CheckOffsetAndSize(s64 offset, s64 size) {
|
||||
return offset >= 0 &&
|
||||
size >= 0 &&
|
||||
offset <= (offset + size);
|
||||
static inline Result CheckOffsetAndSize(s64 offset, s64 size) {
|
||||
R_UNLESS(offset >= 0, fs::ResultInvalidOffset());
|
||||
R_UNLESS(size >= 0, fs::ResultInvalidSize());
|
||||
R_UNLESS(util::CanAddWithoutOverflow<s64>(offset, size), fs::ResultOutOfRange());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
static inline bool CheckOffsetAndSize(s64 offset, size_t size) {
|
||||
return CheckOffsetAndSize(offset, static_cast<s64>(size));
|
||||
static ALWAYS_INLINE Result CheckOffsetAndSize(s64 offset, size_t size) {
|
||||
R_RETURN(CheckOffsetAndSize(offset, static_cast<s64>(size)));
|
||||
}
|
||||
|
||||
static inline Result CheckOffsetAndSizeWithResult(s64 offset, s64 size, Result fail_result) {
|
||||
R_TRY_CATCH(CheckOffsetAndSize(offset, size)) {
|
||||
R_CONVERT_ALL(fail_result);
|
||||
} R_END_TRY_CATCH;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE Result CheckOffsetAndSizeWithResult(s64 offset, size_t size, Result fail_result) {
|
||||
R_RETURN(CheckOffsetAndSizeWithResult(offset, static_cast<s64>(size), fail_result));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -60,23 +73,23 @@ namespace ams::fs {
|
||||
ReadOnlyStorageAdapter(IStorage &s) : m_storage(s) { /* ... */ }
|
||||
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||
return m_storage.Read(offset, buffer, size);
|
||||
R_RETURN(m_storage.Read(offset, buffer, size));
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return m_storage.Flush();
|
||||
R_RETURN(m_storage.Flush());
|
||||
}
|
||||
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
return m_storage.GetSize(out);
|
||||
R_RETURN(m_storage.GetSize(out));
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
R_THROW(fs::ResultUnsupportedOperation());
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
R_THROW(fs::ResultUnsupportedOperation());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -93,9 +106,9 @@ namespace ams::fs {
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Validate arguments and read. */
|
||||
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange());
|
||||
return m_storage.Read(m_offset + offset, buffer, size);
|
||||
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
|
||||
R_TRY(IStorage::CheckAccessRange(offset, size, m_size));
|
||||
R_RETURN(m_storage.Read(m_offset + offset, buffer, size));
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override{
|
||||
@@ -103,22 +116,22 @@ namespace ams::fs {
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Validate arguments and write. */
|
||||
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange());
|
||||
return m_storage.Write(m_offset + offset, buffer, size);
|
||||
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
|
||||
R_TRY(IStorage::CheckAccessRange(offset, size, m_size));
|
||||
R_RETURN(m_storage.Write(m_offset + offset, buffer, size));
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return m_storage.Flush();
|
||||
R_RETURN(m_storage.Flush());
|
||||
}
|
||||
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
*out = m_size;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
return fs::ResultUnsupportedSetSizeForNotResizableSubStorage();
|
||||
R_THROW(fs::ResultUnsupportedSetSizeForNotResizableSubStorage());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -33,11 +33,11 @@ namespace ams::nxboot {
|
||||
ShowFatalError("SdCard: unaligned access to %" PRIx64 ", size=%" PRIx64"\n", static_cast<u64>(offset), static_cast<u64>(size));
|
||||
}
|
||||
|
||||
return ReadSdCard(buffer, size, offset / sdmmc::SectorSize, size / sdmmc::SectorSize);
|
||||
R_RETURN(ReadSdCard(buffer, size, offset / sdmmc::SectorSize, size / sdmmc::SectorSize));
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
@@ -45,15 +45,15 @@ namespace ams::nxboot {
|
||||
R_TRY(GetSdCardMemoryCapacity(std::addressof(num_sectors)));
|
||||
|
||||
*out = static_cast<s64>(num_sectors) * static_cast<s64>(sdmmc::SectorSize);
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
R_THROW(fs::ResultUnsupportedOperation());
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
R_THROW(fs::ResultUnsupportedOperation());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -67,11 +67,11 @@ namespace ams::nxboot {
|
||||
ShowFatalError("SdCard: unaligned access to %" PRIx64 ", size=%" PRIx64"\n", static_cast<u64>(offset), static_cast<u64>(size));
|
||||
}
|
||||
|
||||
return ReadMmc(buffer, size, Partition, offset / sdmmc::SectorSize, size / sdmmc::SectorSize);
|
||||
R_RETURN(ReadMmc(buffer, size, Partition, offset / sdmmc::SectorSize, size / sdmmc::SectorSize));
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
@@ -79,15 +79,15 @@ namespace ams::nxboot {
|
||||
R_TRY(GetMmcMemoryCapacity(std::addressof(num_sectors), Partition));
|
||||
|
||||
*out = num_sectors * sdmmc::SectorSize;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
R_THROW(fs::ResultUnsupportedOperation());
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
R_THROW(fs::ResultUnsupportedOperation());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -153,23 +153,23 @@ namespace ams::nxboot {
|
||||
subofs = 0;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
R_THROW(fs::ResultUnsupportedOperation());
|
||||
}
|
||||
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
R_THROW(fs::ResultUnsupportedOperation());
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
R_THROW(fs::ResultUnsupportedOperation());
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
R_THROW(fs::ResultUnsupportedOperation());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -349,11 +349,11 @@ namespace ams::nxboot {
|
||||
}
|
||||
|
||||
Result ReadBoot0(s64 offset, void *dst, size_t size) {
|
||||
return g_boot0_storage->Read(offset, dst, size);
|
||||
R_RETURN(g_boot0_storage->Read(offset, dst, size));
|
||||
}
|
||||
|
||||
Result ReadPackage2(s64 offset, void *dst, size_t size) {
|
||||
return g_package2_storage->Read(offset, dst, size);
|
||||
R_RETURN(g_package2_storage->Read(offset, dst, size));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace ams::nxboot {
|
||||
/* Write the context to the file. */
|
||||
R_TRY(fs::WriteFile(file, 0, ctx, sizeof(*ctx), fs::WriteOption::Flush));
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,17 +23,17 @@ namespace ams::nxboot {
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = {
|
||||
/* TODO: Update on next change of keys. */
|
||||
0xD2, 0x68, 0xC6, 0x53, 0x9D, 0x94, 0xF9, 0xA8, 0xA5, 0xA8, 0xA7, 0xC8, 0x8F, 0x53, 0x4B, 0x7A
|
||||
0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = {
|
||||
/* TODO: Update on next change of keys. */
|
||||
0xEC, 0x5E, 0xB5, 0x11, 0xD5, 0x43, 0x1E, 0x6A, 0x4E, 0x54, 0x6F, 0xD4, 0xD3, 0x22, 0xCE, 0x87
|
||||
0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = {
|
||||
/* TODO: Update on next change of keys. */
|
||||
0xF0, 0x13, 0x37, 0x9A, 0xD5, 0x63, 0x51, 0xC3, 0xB4, 0x96, 0x35, 0xBC, 0x9C, 0xE8, 0x76, 0x81
|
||||
0x6E, 0x77, 0x86, 0xAC, 0x83, 0x0A, 0x8D, 0x3E, 0x7D, 0xB7, 0x66, 0xA0, 0x22, 0xB7, 0x6E, 0x67
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
|
||||
@@ -68,6 +68,7 @@ namespace ams::nxboot {
|
||||
{ 0xAA, 0xFD, 0xBC, 0xBB, 0x25, 0xC3, 0xA4, 0xEF, 0xE3, 0xEE, 0x58, 0x53, 0xB7, 0xF8, 0xDD, 0xD6 }, /* 12.1.0 Device Master Key Source Source. */
|
||||
{ 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F }, /* 13.0.0 Device Master Key Source Source. */
|
||||
{ 0x5B, 0x94, 0x63, 0xF7, 0xAD, 0x96, 0x1B, 0xA6, 0x23, 0x30, 0x06, 0x4D, 0x01, 0xE4, 0xCE, 0x1D }, /* 14.0.0 Device Master Key Source Source. */
|
||||
{ 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 }, /* 15.0.0 Device Master Key Source Source. */
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||
@@ -82,6 +83,7 @@ namespace ams::nxboot {
|
||||
{ 0xC2, 0x65, 0x34, 0x6E, 0xC7, 0xC6, 0x5D, 0x97, 0x3E, 0x34, 0x5C, 0x6B, 0xB3, 0x7E, 0xC6, 0xE3 }, /* 12.1.0 Device Master Kek Source. */
|
||||
{ 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 }, /* 13.0.0 Device Master Kek Source. */
|
||||
{ 0x67, 0xD5, 0xD6, 0x0C, 0x08, 0xF5, 0xA3, 0x11, 0xBD, 0x6D, 0x5A, 0xEB, 0x96, 0x24, 0xB0, 0xD2 }, /* 14.0.0 Device Master Kek Source. */
|
||||
{ 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 }, /* 15.0.0 Device Master Kek Source. */
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||
@@ -96,6 +98,7 @@ namespace ams::nxboot {
|
||||
{ 0xC4, 0xBB, 0xF3, 0x9F, 0xA3, 0xAA, 0x00, 0x99, 0x7C, 0x97, 0xAD, 0x91, 0x8F, 0xE8, 0x45, 0xCB }, /* 12.1.0 Device Master Kek Source. */
|
||||
{ 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F }, /* 13.0.0 Device Master Kek Source. */
|
||||
{ 0xCE, 0x14, 0x74, 0x66, 0x98, 0xA8, 0x6D, 0x7D, 0xBD, 0x54, 0x91, 0x68, 0x5F, 0x1D, 0x0E, 0xEA }, /* 14.0.0 Device Master Kek Source. */
|
||||
{ 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E }, /* 15.0.0 Device Master Kek Source. */
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
||||
@@ -113,6 +116,7 @@ namespace ams::nxboot {
|
||||
{ 0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98 }, /* Master key 0A encrypted with Master key 0B. */
|
||||
{ 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 }, /* Master key 0B encrypted with Master key 0C. */
|
||||
{ 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 }, /* Master key 0C encrypted with Master key 0D. */
|
||||
{ 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 }, /* Master key 0D encrypted with Master key 0E. */
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
||||
@@ -130,6 +134,7 @@ namespace ams::nxboot {
|
||||
{ 0x21, 0x88, 0x6B, 0x10, 0x9E, 0x83, 0xD6, 0x52, 0xAB, 0x08, 0xDB, 0x6D, 0x39, 0xFF, 0x1C, 0x9C }, /* Master key 0A encrypted with Master key 0B. */
|
||||
{ 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 }, /* Master key 0B encrypted with Master key 0C. */
|
||||
{ 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 }, /* Master key 0C encrypted with Master key 0D. */
|
||||
{ 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D }, /* Master key 0D encrypted with Master key 0E. */
|
||||
};
|
||||
|
||||
alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {};
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace ams::nxboot {
|
||||
g_mmc_partition = partition;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,29 +47,29 @@ namespace ams::nxboot {
|
||||
sdmmc::SetMmcWorkBuffer(MmcPort, g_mmc_work_buffer, sizeof(g_mmc_work_buffer));
|
||||
|
||||
/* Activate the mmc. */
|
||||
return sdmmc::Activate(MmcPort);
|
||||
R_RETURN(sdmmc::Activate(MmcPort));
|
||||
}
|
||||
|
||||
Result CheckMmcConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw) {
|
||||
return sdmmc::CheckMmcConnection(out_sm, out_bw, MmcPort);
|
||||
R_RETURN(sdmmc::CheckMmcConnection(out_sm, out_bw, MmcPort));
|
||||
}
|
||||
|
||||
Result GetMmcMemoryCapacity(u32 *out_num_sectors, sdmmc::MmcPartition partition) {
|
||||
if (partition == sdmmc::MmcPartition_UserData) {
|
||||
return sdmmc::GetDeviceMemoryCapacity(out_num_sectors, MmcPort);
|
||||
R_RETURN(sdmmc::GetDeviceMemoryCapacity(out_num_sectors, MmcPort));
|
||||
} else {
|
||||
return sdmmc::GetMmcBootPartitionCapacity(out_num_sectors, MmcPort);
|
||||
R_RETURN(sdmmc::GetMmcBootPartitionCapacity(out_num_sectors, MmcPort));
|
||||
}
|
||||
}
|
||||
|
||||
Result ReadMmc(void *dst, size_t size, sdmmc::MmcPartition partition, size_t sector_index, size_t sector_count) {
|
||||
R_TRY(SelectMmcPartition(partition));
|
||||
return sdmmc::Read(dst, size, MmcPort, sector_index, sector_count);
|
||||
R_RETURN(sdmmc::Read(dst, size, MmcPort, sector_index, sector_count));
|
||||
}
|
||||
|
||||
Result WriteMmc(sdmmc::MmcPartition partition, size_t sector_index, size_t sector_count, const void *src, size_t size) {
|
||||
R_TRY(SelectMmcPartition(partition));
|
||||
return sdmmc::Write(MmcPort, sector_index, sector_count, src, size);
|
||||
R_RETURN(sdmmc::Write(MmcPort, sector_index, sector_count, src, size));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -80,7 +80,7 @@ namespace ams::nxboot {
|
||||
}
|
||||
|
||||
/* Check that the key generation is one that we can use. */
|
||||
static_assert(pkg1::KeyGeneration_Count == 14);
|
||||
static_assert(pkg1::KeyGeneration_Count == 15);
|
||||
if (key_generation >= pkg1::KeyGeneration_Count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace ams::nxboot {
|
||||
sdmmc::SetSdCardWorkBuffer(SdCardPort, g_sd_work_buffer, sizeof(g_sd_work_buffer));
|
||||
|
||||
/* Activate the SD card. */
|
||||
return sdmmc::Activate(SdCardPort);
|
||||
R_RETURN(sdmmc::Activate(SdCardPort));
|
||||
}
|
||||
|
||||
void FinalizeSdCard() {
|
||||
@@ -90,19 +90,19 @@ namespace ams::nxboot {
|
||||
}
|
||||
|
||||
Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw) {
|
||||
return sdmmc::CheckSdCardConnection(out_sm, out_bw, SdCardPort);
|
||||
R_RETURN(sdmmc::CheckSdCardConnection(out_sm, out_bw, SdCardPort));
|
||||
}
|
||||
|
||||
Result GetSdCardMemoryCapacity(u32 *out_num_sectors) {
|
||||
return sdmmc::GetDeviceMemoryCapacity(out_num_sectors, SdCardPort);
|
||||
R_RETURN(sdmmc::GetDeviceMemoryCapacity(out_num_sectors, SdCardPort));
|
||||
}
|
||||
|
||||
Result ReadSdCard(void *dst, size_t size, size_t sector_index, size_t sector_count) {
|
||||
return sdmmc::Read(dst, size, SdCardPort, sector_index, sector_count);
|
||||
R_RETURN(sdmmc::Read(dst, size, SdCardPort, sector_index, sector_count));
|
||||
}
|
||||
|
||||
Result WriteSdCard(size_t sector_index, size_t sector_count, const void *src, size_t size) {
|
||||
return sdmmc::Write(SdCardPort, sector_index, sector_count, src, size);
|
||||
R_RETURN(sdmmc::Write(SdCardPort, sector_index, sector_count, src, size));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -253,6 +253,8 @@ namespace ams::nxboot {
|
||||
return ams::TargetFirmware_13_2_1;
|
||||
} else if (std::memcmp(package1 + 0x10, "20220209", 8) == 0) {
|
||||
return ams::TargetFirmware_14_0_0;
|
||||
} else if (std::memcmp(package1 + 0x10, "20220801", 8) == 0) {
|
||||
return ams::TargetFirmware_15_0_0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -156,6 +156,9 @@ namespace ams::nxboot {
|
||||
FsVersion_14_0_0,
|
||||
FsVersion_14_0_0_Exfat,
|
||||
|
||||
FsVersion_15_0_0,
|
||||
FsVersion_15_0_0_Exfat,
|
||||
|
||||
FsVersion_Count,
|
||||
};
|
||||
|
||||
@@ -227,6 +230,10 @@ namespace ams::nxboot {
|
||||
|
||||
{ 0x88, 0x7A, 0xC1, 0x50, 0x80, 0x6C, 0x75, 0xCC }, /* FsVersion_14_0_0 */
|
||||
{ 0xD4, 0x88, 0xD1, 0xF2, 0x92, 0x17, 0x35, 0x5C }, /* FsVersion_14_0_0_Exfat */
|
||||
|
||||
|
||||
{ 0xD0, 0xD4, 0x49, 0x18, 0x14, 0xB5, 0x62, 0xAF }, /* FsVersion_15_0_0 */
|
||||
{ 0x34, 0xC0, 0xD9, 0xED, 0x6A, 0xD1, 0x87, 0x3D }, /* FsVersion_15_0_0_Exfat */
|
||||
};
|
||||
|
||||
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
|
||||
@@ -628,6 +635,14 @@ namespace ams::nxboot {
|
||||
AddPatch(fs_meta, 0x195769, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x16F6B0, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
case FsVersion_15_0_0:
|
||||
AddPatch(fs_meta, 0x184259, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x15EDE4, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
case FsVersion_15_0_0_Exfat:
|
||||
AddPatch(fs_meta, 0x18F1E9, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x169D74, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,6 @@ namespace ams::nxboot {
|
||||
HANDLE_DRAM_CASE( 3, 12)
|
||||
HANDLE_DRAM_CASE( 5, 12)
|
||||
HANDLE_DRAM_CASE( 6, 12)
|
||||
HANDLE_DRAM_CASE( 7, 0)
|
||||
HANDLE_DRAM_CASE( 8, 1)
|
||||
HANDLE_DRAM_CASE( 9, 2)
|
||||
HANDLE_DRAM_CASE(10, 3)
|
||||
@@ -94,7 +93,6 @@ namespace ams::nxboot {
|
||||
HANDLE_DRAM_CASE(13, 2)
|
||||
HANDLE_DRAM_CASE(14, 3)
|
||||
HANDLE_DRAM_CASE(15, 4)
|
||||
HANDLE_DRAM_CASE(16, 5)
|
||||
HANDLE_DRAM_CASE(17, 6)
|
||||
HANDLE_DRAM_CASE(18, 7)
|
||||
HANDLE_DRAM_CASE(19, 6)
|
||||
@@ -107,6 +105,12 @@ namespace ams::nxboot {
|
||||
HANDLE_DRAM_CASE(26, 11)
|
||||
HANDLE_DRAM_CASE(27, 11)
|
||||
HANDLE_DRAM_CASE(28, 7)
|
||||
HANDLE_DRAM_CASE(29, 0)
|
||||
HANDLE_DRAM_CASE(30, 0)
|
||||
HANDLE_DRAM_CASE(31, 0)
|
||||
HANDLE_DRAM_CASE(32, 5)
|
||||
HANDLE_DRAM_CASE(33, 5)
|
||||
HANDLE_DRAM_CASE(34, 5)
|
||||
default:
|
||||
AMS_ABORT("Invalid DRAM id");
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||
branch = master
|
||||
commit = 726a7efddf8d2950e1b12848cecb66f17fbdde37
|
||||
parent = 44d553d12ebac4051f2a1adbc12aeff5b3d905d9
|
||||
commit = b2232894f31953511d33bc665f68216badc3bb07
|
||||
parent = 8ce4f1961580a09381e486cc51c160a00fa86b88
|
||||
method = merge
|
||||
cmdver = 0.4.1
|
||||
|
||||
@@ -67,7 +67,7 @@ endif
|
||||
|
||||
ifeq ($(ATMOSPHERE_BOARD),nx-hac-001)
|
||||
export LDFLAGS = -specs=$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/stratosphere.specs -specs=$(DEVKITPRO)/libnx/switch.specs $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-Map,$(notdir $*.map)
|
||||
else ifeq ($(ATMOSPHERE_COMPILER_NAME),clang)
|
||||
else ifeq ($(ATMOSPHERE_OS_NAME),macos)
|
||||
export LDFLAGS = $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-map,$(notdir $@.map)
|
||||
else
|
||||
export LDFLAGS = $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-Map,$(notdir $@.map)
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace ams::fuse {
|
||||
DramId_IcosaSamsung6GB = 4,
|
||||
DramId_HoagHynix1y4GB = 5,
|
||||
DramId_AulaHynix1y4GB = 6,
|
||||
DramId_IowaX1X2Samsung4GB = 7,
|
||||
DramId_Deprecated7 = 7,
|
||||
DramId_IowaSansung4GB = 8,
|
||||
DramId_IowaSamsung8GB = 9,
|
||||
DramId_IowaHynix4GB = 10,
|
||||
@@ -64,7 +64,7 @@ namespace ams::fuse {
|
||||
DramId_HoagSamsung8GB = 13,
|
||||
DramId_HoagHynix4GB = 14,
|
||||
DramId_HoagMicron4GB = 15,
|
||||
DramId_IowaSamsung4GBY = 16,
|
||||
DramId_Deprecated16 = 16,
|
||||
DramId_IowaSamsung1y4GBX = 17,
|
||||
DramId_IowaSamsung1y8GBX = 18,
|
||||
DramId_HoagSamsung1y4GBX = 19,
|
||||
@@ -77,6 +77,12 @@ namespace ams::fuse {
|
||||
DramId_HoagMicron1y4GB = 26,
|
||||
DramId_AulaMicron1y4GB = 27,
|
||||
DramId_AulaSamsung1y8GBX = 28,
|
||||
DramId_IowaX1X2Samsung4GB = 29,
|
||||
DramId_HoagX1X2Samsung4GB = 30,
|
||||
DramId_AulaX1X2Samsung4GB = 31,
|
||||
DramId_IowaSamsung4GBY = 32,
|
||||
DramId_HoagSamsung4GBY = 33,
|
||||
DramId_AulaSamsung4GBY = 34,
|
||||
|
||||
DramId_Count,
|
||||
};
|
||||
@@ -119,4 +125,4 @@ namespace ams::fuse {
|
||||
bool IsOdmProductionMode();
|
||||
void ConfigureFuseBypass();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace ams::pkg1 {
|
||||
KeyGeneration_12_1_0 = 0x0B,
|
||||
KeyGeneration_13_0_0 = 0x0C,
|
||||
KeyGeneration_14_0_0 = 0x0D,
|
||||
KeyGeneration_15_0_0 = 0x0E,
|
||||
|
||||
KeyGeneration_Count,
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace ams::pkg2 {
|
||||
|
||||
constexpr inline int PayloadCount = 3;
|
||||
|
||||
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x15 in Nintendo's code. */
|
||||
constexpr inline int CurrentBootloaderVersion = 0x11;
|
||||
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x16 in Nintendo's code. */
|
||||
constexpr inline int CurrentBootloaderVersion = 0x12;
|
||||
|
||||
struct Package2Meta {
|
||||
using Magic = util::FourCC<'P','K','2','1'>;
|
||||
|
||||
@@ -39,12 +39,13 @@ namespace ams::fuse {
|
||||
struct OdmWord4 {
|
||||
using HardwareState1 = util::BitPack32::Field<0, 2, int>;
|
||||
using HardwareType1 = util::BitPack32::Field<HardwareState1::Next, 1, int>;
|
||||
using DramId = util::BitPack32::Field<HardwareType1::Next, 5, int>;
|
||||
using HardwareType2 = util::BitPack32::Field<DramId::Next, 1, int>;
|
||||
using DramId1 = util::BitPack32::Field<HardwareType1::Next, 5, int>;
|
||||
using HardwareType2 = util::BitPack32::Field<DramId1::Next, 1, int>;
|
||||
using HardwareState2 = util::BitPack32::Field<HardwareType2::Next, 1, int>;
|
||||
using RetailInteractiveDisplayState = util::BitPack32::Field<HardwareState2::Next, 1, int>;
|
||||
using FormatVersion = util::BitPack32::Field<RetailInteractiveDisplayState::Next, 1, int>;
|
||||
using Reserved = util::BitPack32::Field<FormatVersion::Next, 4, int>;
|
||||
using DramId2 = util::BitPack32::Field<FormatVersion::Next, 3, int>;
|
||||
using Reserved = util::BitPack32::Field<DramId2::Next, 1, int>;
|
||||
using HardwareType3 = util::BitPack32::Field<Reserved::Next, 4, int>;
|
||||
};
|
||||
|
||||
@@ -71,6 +72,15 @@ namespace ams::fuse {
|
||||
(odm_word4.Get<OdmWord4::HardwareType3>() << HardwareType3Shift);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE int GetDramIdValue(const util::BitPack32 odm_word4) {
|
||||
constexpr auto DramId1Shift = 0;
|
||||
constexpr auto DramId2Shift = OdmWord4::DramId1::Count + DramId1Shift;
|
||||
|
||||
|
||||
return (odm_word4.Get<OdmWord4::DramId1>() << DramId1Shift) |
|
||||
(odm_word4.Get<OdmWord4::DramId2>() << DramId2Shift);
|
||||
}
|
||||
|
||||
constinit uintptr_t g_register_address = secmon::MemoryRegionPhysicalDeviceFuses.GetAddress();
|
||||
|
||||
constinit bool g_checked_for_rcm_bug_patch = false;
|
||||
@@ -167,6 +177,7 @@ namespace ams::fuse {
|
||||
}
|
||||
|
||||
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
||||
TargetFirmware_15_0_0,
|
||||
TargetFirmware_13_2_1,
|
||||
TargetFirmware_12_0_2,
|
||||
TargetFirmware_11_0_0,
|
||||
@@ -305,7 +316,8 @@ namespace ams::fuse {
|
||||
}
|
||||
|
||||
DramId GetDramId() {
|
||||
return static_cast<DramId>(util::BitPack32{GetCommonOdmWord(4)}.Get<OdmWord4::DramId>());
|
||||
/* Get the value. */
|
||||
return static_cast<DramId>(GetDramIdValue(util::BitPack32{GetCommonOdmWord(4)}));
|
||||
}
|
||||
|
||||
HardwareType GetHardwareType() {
|
||||
|
||||
@@ -178,7 +178,7 @@ namespace ams::kern::arch::arm64 {
|
||||
}
|
||||
|
||||
NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
|
||||
NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit);
|
||||
NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit);
|
||||
Result Finalize();
|
||||
private:
|
||||
Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
||||
@@ -208,7 +208,7 @@ namespace ams::kern::arch::arm64 {
|
||||
}
|
||||
}
|
||||
|
||||
Result MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
||||
Result MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll);
|
||||
Result MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
||||
|
||||
bool MergePages(KProcessAddress virt_addr, PageLinkedList *page_list);
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace ams::kern::arch::arm64 {
|
||||
m_page_table.Activate(id);
|
||||
}
|
||||
|
||||
Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit) {
|
||||
R_RETURN(m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, mem_block_slab_manager, block_info_manager, pt_manager, resource_limit));
|
||||
Result Initialize(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
||||
R_RETURN(m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, system_resource, resource_limit));
|
||||
}
|
||||
|
||||
void Finalize() { m_page_table.Finalize(); }
|
||||
@@ -110,6 +110,14 @@ namespace ams::kern::arch::arm64 {
|
||||
R_RETURN(m_page_table.MapRegion(region_type, perm));
|
||||
}
|
||||
|
||||
Result MapInsecureMemory(KProcessAddress address, size_t size) {
|
||||
R_RETURN(m_page_table.MapInsecureMemory(address, size));
|
||||
}
|
||||
|
||||
Result UnmapInsecureMemory(KProcessAddress address, size_t size) {
|
||||
R_RETURN(m_page_table.UnmapInsecureMemory(address, size));
|
||||
}
|
||||
|
||||
Result MapPageGroup(KProcessAddress addr, const KPageGroup &pg, KMemoryState state, KMemoryPermission perm) {
|
||||
R_RETURN(m_page_table.MapPageGroup(addr, pg, state, perm));
|
||||
}
|
||||
@@ -158,12 +166,12 @@ namespace ams::kern::arch::arm64 {
|
||||
R_RETURN(m_page_table.WriteDebugIoMemory(address, buffer, size));
|
||||
}
|
||||
|
||||
Result LockForMapDeviceAddressSpace(KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
|
||||
R_RETURN(m_page_table.LockForMapDeviceAddressSpace(address, size, perm, is_aligned));
|
||||
Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) {
|
||||
R_RETURN(m_page_table.LockForMapDeviceAddressSpace(out_is_io, address, size, perm, is_aligned, check_heap));
|
||||
}
|
||||
|
||||
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size) {
|
||||
R_RETURN(m_page_table.LockForUnmapDeviceAddressSpace(address, size));
|
||||
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap) {
|
||||
R_RETURN(m_page_table.LockForUnmapDeviceAddressSpace(address, size, check_heap));
|
||||
}
|
||||
|
||||
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) {
|
||||
|
||||
@@ -44,8 +44,8 @@ namespace ams::kern::board::generic {
|
||||
R_THROW(ams::kern::svc::ResultNotImplemented());
|
||||
}
|
||||
|
||||
Result ALWAYS_INLINE Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) {
|
||||
MESOSPHERE_UNUSED(page_table, process_address, size, device_address, device_perm, is_aligned);
|
||||
Result ALWAYS_INLINE Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool is_io) {
|
||||
MESOSPHERE_UNUSED(page_table, process_address, size, device_address, device_perm, is_aligned, is_io);
|
||||
R_THROW(ams::kern::svc::ResultNotImplemented());
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
Result Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size);
|
||||
Result Detach(ams::svc::DeviceName device_name);
|
||||
|
||||
Result Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned);
|
||||
Result Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool is_io);
|
||||
Result Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address);
|
||||
|
||||
void Unmap(KDeviceVirtualAddress device_address, size_t size) {
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
class KSystemControl : public KSystemControlBase {
|
||||
public:
|
||||
/* This can be overridden as needed. */
|
||||
static constexpr size_t SecureAppletMemorySize = 4_MB;
|
||||
public:
|
||||
class Init : public KSystemControlBase::Init {
|
||||
public:
|
||||
|
||||
@@ -36,13 +36,13 @@ namespace ams::kern::init {
|
||||
size_t num_KDebug;
|
||||
size_t num_KIoPool;
|
||||
size_t num_KIoRegion;
|
||||
size_t num_KSessionRequestMappings;
|
||||
};
|
||||
|
||||
NOINLINE void InitializeSlabResourceCounts();
|
||||
const KSlabResourceCounts &GetSlabResourceCounts();
|
||||
|
||||
size_t CalculateTotalSlabHeapSize();
|
||||
NOINLINE void InitializeKPageBufferSlabHeap();
|
||||
NOINLINE void InitializeSlabHeaps();
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace ams::kern {
|
||||
|
||||
class KAutoObject;
|
||||
|
||||
class KSystemResource;
|
||||
|
||||
#define FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(HANDLER) \
|
||||
HANDLER(KAutoObject) \
|
||||
\
|
||||
@@ -48,7 +50,8 @@ namespace ams::kern {
|
||||
HANDLER(KSessionRequest) \
|
||||
HANDLER(KCodeMemory) \
|
||||
HANDLER(KIoPool) \
|
||||
HANDLER(KIoRegion)
|
||||
HANDLER(KIoRegion) \
|
||||
HANDLER(KSystemResource)
|
||||
|
||||
class KClassTokenGenerator {
|
||||
public:
|
||||
@@ -95,7 +98,7 @@ namespace ams::kern {
|
||||
if constexpr (std::is_same<T, KAutoObject>::value) {
|
||||
static_assert(T::ObjectType == ObjectType::KAutoObject);
|
||||
return 0;
|
||||
} else if constexpr (!std::is_final<T>::value) {
|
||||
} else if constexpr (!std::is_final<T>::value && !std::same_as<T, KSystemResource>) {
|
||||
static_assert(ObjectType::BaseClassesStart <= T::ObjectType && T::ObjectType < ObjectType::BaseClassesEnd);
|
||||
constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) - static_cast<TokenBaseType>(ObjectType::BaseClassesStart);
|
||||
return BaseClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>();
|
||||
@@ -142,6 +145,12 @@ namespace ams::kern {
|
||||
KIoPool,
|
||||
KIoRegion,
|
||||
|
||||
/* NOTE: What occupies these gaps? They can be inferred, but they don't make sense. */
|
||||
KAlpha,
|
||||
KBeta,
|
||||
|
||||
KSystemResource,
|
||||
|
||||
FinalClassesLast,
|
||||
|
||||
FinalClassesEnd = FinalClassesStart + NumFinalClasses,
|
||||
@@ -178,8 +187,10 @@ namespace ams::kern {
|
||||
}
|
||||
|
||||
for (auto fin = util::ToUnderlying(KClassTokenGenerator::ObjectType::FinalClassesStart); fin < util::ToUnderlying(KClassTokenGenerator::ObjectType::FinalClassesLast); ++fin) {
|
||||
if (!IsObjectTypeIncludedByMacro(static_cast<KClassTokenGenerator::ObjectType>(fin))) {
|
||||
return false;
|
||||
if (const auto o = static_cast<KClassTokenGenerator::ObjectType>(fin); !IsObjectTypeIncludedByMacro(o)) {
|
||||
if (o != KClassTokenGenerator::ObjectType::KAlpha && o != KClassTokenGenerator::ObjectType::KBeta) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,17 +41,17 @@ namespace ams::kern {
|
||||
Result Attach(ams::svc::DeviceName device_name);
|
||||
Result Detach(ams::svc::DeviceName device_name);
|
||||
|
||||
Result MapByForce(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, ams::svc::MemoryPermission device_perm) {
|
||||
R_RETURN(this->Map(page_table, process_address, size, device_address, device_perm, false));
|
||||
Result MapByForce(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option) {
|
||||
R_RETURN(this->Map(page_table, process_address, size, device_address, option, false));
|
||||
}
|
||||
|
||||
Result MapAligned(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, ams::svc::MemoryPermission device_perm) {
|
||||
R_RETURN(this->Map(page_table, process_address, size, device_address, device_perm, true));
|
||||
Result MapAligned(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option) {
|
||||
R_RETURN(this->Map(page_table, process_address, size, device_address, option, true));
|
||||
}
|
||||
|
||||
Result Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address);
|
||||
private:
|
||||
Result Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, ams::svc::MemoryPermission device_perm, bool is_aligned);
|
||||
Result Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option, bool is_aligned);
|
||||
public:
|
||||
static void Initialize();
|
||||
};
|
||||
|
||||
@@ -38,30 +38,37 @@ namespace ams::kern {
|
||||
size_t m_peak;
|
||||
size_t m_count;
|
||||
KVirtualAddress m_address;
|
||||
KVirtualAddress m_aligned_address;
|
||||
size_t m_size;
|
||||
public:
|
||||
KDynamicPageManager() : m_lock(), m_page_bitmap(), m_used(), m_peak(), m_count(), m_address(Null<KVirtualAddress>), m_size() { /* ... */ }
|
||||
KDynamicPageManager() : m_lock(), m_page_bitmap(), m_used(), m_peak(), m_count(), m_address(Null<KVirtualAddress>), m_aligned_address(Null<KVirtualAddress>), m_size() { /* ... */ }
|
||||
|
||||
Result Initialize(KVirtualAddress memory, size_t sz) {
|
||||
Result Initialize(KVirtualAddress memory, size_t size, size_t align) {
|
||||
/* We need to have positive size. */
|
||||
R_UNLESS(sz > 0, svc::ResultOutOfMemory());
|
||||
R_UNLESS(size > 0, svc::ResultOutOfMemory());
|
||||
|
||||
/* Calculate management overhead. */
|
||||
const size_t management_size = KPageBitmap::CalculateManagementOverheadSize(sz / sizeof(PageBuffer));
|
||||
const size_t allocatable_size = sz - management_size;
|
||||
/* Set addresses. */
|
||||
m_address = memory;
|
||||
m_aligned_address = util::AlignDown(GetInteger(memory), align);
|
||||
|
||||
/* Calculate extents. */
|
||||
const size_t managed_size = m_address + size - m_aligned_address;
|
||||
const size_t overhead_size = util::AlignUp(KPageBitmap::CalculateManagementOverheadSize(managed_size / sizeof(PageBuffer)), sizeof(PageBuffer));
|
||||
R_UNLESS(overhead_size < size, svc::ResultOutOfMemory());
|
||||
|
||||
/* Set tracking fields. */
|
||||
m_address = memory;
|
||||
m_size = util::AlignDown(allocatable_size, sizeof(PageBuffer));
|
||||
m_count = allocatable_size / sizeof(PageBuffer);
|
||||
R_UNLESS(m_count > 0, svc::ResultOutOfMemory());
|
||||
m_size = util::AlignDown(size - overhead_size, sizeof(PageBuffer));
|
||||
m_count = m_size / sizeof(PageBuffer);
|
||||
|
||||
/* Clear the management region. */
|
||||
u64 *management_ptr = GetPointer<u64>(m_address + allocatable_size);
|
||||
std::memset(management_ptr, 0, management_size);
|
||||
u64 *management_ptr = GetPointer<u64>(m_address + size - overhead_size);
|
||||
std::memset(management_ptr, 0, overhead_size);
|
||||
|
||||
/* Initialize the bitmap. */
|
||||
m_page_bitmap.Initialize(management_ptr, m_count);
|
||||
const size_t allocatable_region_size = (GetInteger(m_address) + size - overhead_size) - GetInteger(m_aligned_address);
|
||||
MESOSPHERE_ABORT_UNLESS(allocatable_region_size >= sizeof(PageBuffer));
|
||||
|
||||
m_page_bitmap.Initialize(management_ptr, allocatable_region_size / sizeof(PageBuffer));
|
||||
|
||||
/* Free the pages to the bitmap. */
|
||||
for (size_t i = 0; i < m_count; i++) {
|
||||
@@ -69,7 +76,7 @@ namespace ams::kern {
|
||||
cpu::ClearPageToZero(GetPointer<PageBuffer>(m_address) + i);
|
||||
|
||||
/* Set the bit for the free page. */
|
||||
m_page_bitmap.SetBit(i);
|
||||
m_page_bitmap.SetBit((GetInteger(m_address) + (i * sizeof(PageBuffer)) - GetInteger(m_aligned_address)) / sizeof(PageBuffer));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
@@ -98,7 +105,28 @@ namespace ams::kern {
|
||||
m_page_bitmap.ClearBit(offset);
|
||||
m_peak = std::max(m_peak, (++m_used));
|
||||
|
||||
return GetPointer<PageBuffer>(m_address) + offset;
|
||||
return GetPointer<PageBuffer>(m_aligned_address) + offset;
|
||||
}
|
||||
|
||||
PageBuffer *Allocate(size_t count) {
|
||||
/* Take the lock. */
|
||||
KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
/* Find a random free block. */
|
||||
ssize_t soffset = m_page_bitmap.FindFreeRange(count);
|
||||
if (AMS_UNLIKELY(soffset < 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const size_t offset = static_cast<size_t>(soffset);
|
||||
|
||||
/* Update our tracking. */
|
||||
m_page_bitmap.ClearRange(offset, count);
|
||||
m_used += count;
|
||||
m_peak = std::max(m_peak, m_used);
|
||||
|
||||
return GetPointer<PageBuffer>(m_aligned_address) + offset;
|
||||
}
|
||||
|
||||
void Free(PageBuffer *pb) {
|
||||
@@ -110,7 +138,7 @@ namespace ams::kern {
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
/* Set the bit for the free page. */
|
||||
size_t offset = (reinterpret_cast<uintptr_t>(pb) - GetInteger(m_address)) / sizeof(PageBuffer);
|
||||
size_t offset = (reinterpret_cast<uintptr_t>(pb) - GetInteger(m_aligned_address)) / sizeof(PageBuffer);
|
||||
m_page_bitmap.SetBit(offset);
|
||||
|
||||
/* Decrement our used count. */
|
||||
|
||||
@@ -70,15 +70,20 @@ namespace ams::kern {
|
||||
u16 m_next_linear_id;
|
||||
u16 m_count;
|
||||
public:
|
||||
constexpr explicit KHandleTable(util::ConstantInitializeTag) : m_entry_infos(), m_objects(), m_lock(), m_free_head_index(-1), m_table_size(), m_max_count(), m_next_linear_id(MinLinearId), m_count() { /* ... */ }
|
||||
constexpr explicit KHandleTable(util::ConstantInitializeTag) : m_entry_infos(), m_objects(), m_lock(), m_free_head_index(-1), m_table_size(), m_max_count(), m_next_linear_id(), m_count() { /* ... */ }
|
||||
|
||||
explicit KHandleTable() : m_lock(), m_free_head_index(-1), m_count() { MESOSPHERE_ASSERT_THIS(); }
|
||||
explicit KHandleTable() : m_lock(), m_free_head_index(-1), m_table_size(), m_max_count(), m_next_linear_id(), m_count() { MESOSPHERE_ASSERT_THIS(); }
|
||||
|
||||
constexpr MESOSPHERE_NOINLINE_IF_DEBUG Result Initialize(s32 size) {
|
||||
MESOSPHERE_NOINLINE_IF_DEBUG Result Initialize(s32 size) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Check that the table size is valid. */
|
||||
R_UNLESS(size <= static_cast<s32>(MaxTableSize), svc::ResultOutOfMemory());
|
||||
|
||||
/* Lock. */
|
||||
KScopedDisableDispatch dd;
|
||||
KScopedSpinLock lk(m_lock);
|
||||
|
||||
/* Initialize all fields. */
|
||||
m_max_count = 0;
|
||||
m_table_size = (size <= 0) ? MaxTableSize : size;
|
||||
|
||||
@@ -22,9 +22,7 @@
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
class KInterruptEventTask;
|
||||
|
||||
class KInterruptEvent final : public KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent> {
|
||||
class KInterruptEvent final : public KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent>, public KInterruptTask {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KInterruptEvent, KReadableEvent);
|
||||
private:
|
||||
s32 m_interrupt_id;
|
||||
@@ -54,21 +52,9 @@ namespace ams::kern {
|
||||
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
|
||||
|
||||
constexpr s32 GetInterruptId() const { return m_interrupt_id; }
|
||||
};
|
||||
|
||||
class KInterruptEventTask : public KSlabAllocated<KInterruptEventTask>, public KInterruptTask {
|
||||
private:
|
||||
KInterruptEvent *m_event;
|
||||
public:
|
||||
constexpr KInterruptEventTask() : m_event(nullptr) { /* ... */ }
|
||||
~KInterruptEventTask() { /* ... */ }
|
||||
|
||||
virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override;
|
||||
virtual void DoTask() override;
|
||||
|
||||
void Unregister(s32 interrupt_id, s32 core_id);
|
||||
public:
|
||||
static Result Register(s32 interrupt_id, s32 core_id, bool level, KInterruptEvent *event);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace ams::kern {
|
||||
KMemoryState_FlagCanMapProcess = (1 << 23),
|
||||
KMemoryState_FlagCanChangeAttribute = (1 << 24),
|
||||
KMemoryState_FlagCanCodeMemory = (1 << 25),
|
||||
KMemoryState_FlagLinearMapped = (1 << 26),
|
||||
|
||||
KMemoryState_FlagsData = KMemoryState_FlagCanReprotect | KMemoryState_FlagCanUseIpc |
|
||||
KMemoryState_FlagCanUseNonDeviceIpc | KMemoryState_FlagCanUseNonSecureIpc |
|
||||
@@ -50,25 +51,27 @@ namespace ams::kern {
|
||||
KMemoryState_FlagCanTransfer | KMemoryState_FlagCanQueryPhysical |
|
||||
KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap |
|
||||
KMemoryState_FlagCanIpcUserBuffer | KMemoryState_FlagReferenceCounted |
|
||||
KMemoryState_FlagCanChangeAttribute,
|
||||
KMemoryState_FlagCanChangeAttribute | KMemoryState_FlagLinearMapped,
|
||||
|
||||
KMemoryState_FlagsCode = KMemoryState_FlagCanDebug | KMemoryState_FlagCanUseIpc |
|
||||
KMemoryState_FlagCanUseNonDeviceIpc | KMemoryState_FlagCanUseNonSecureIpc |
|
||||
KMemoryState_FlagMapped | KMemoryState_FlagCode |
|
||||
KMemoryState_FlagCanQueryPhysical | KMemoryState_FlagCanDeviceMap |
|
||||
KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagReferenceCounted,
|
||||
KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagReferenceCounted |
|
||||
KMemoryState_FlagLinearMapped,
|
||||
|
||||
KMemoryState_FlagsMisc = KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted |
|
||||
KMemoryState_FlagCanQueryPhysical | KMemoryState_FlagCanDeviceMap,
|
||||
KMemoryState_FlagCanQueryPhysical | KMemoryState_FlagCanDeviceMap |
|
||||
KMemoryState_FlagLinearMapped,
|
||||
|
||||
|
||||
KMemoryState_Free = ams::svc::MemoryState_Free,
|
||||
KMemoryState_Io = ams::svc::MemoryState_Io | KMemoryState_FlagMapped,
|
||||
KMemoryState_Io = ams::svc::MemoryState_Io | KMemoryState_FlagMapped | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap,
|
||||
KMemoryState_Static = ams::svc::MemoryState_Static | KMemoryState_FlagMapped | KMemoryState_FlagCanQueryPhysical,
|
||||
KMemoryState_Code = ams::svc::MemoryState_Code | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess,
|
||||
KMemoryState_CodeData = ams::svc::MemoryState_CodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeMemory,
|
||||
KMemoryState_Normal = ams::svc::MemoryState_Normal | KMemoryState_FlagsData | KMemoryState_FlagCanCodeMemory,
|
||||
KMemoryState_Shared = ams::svc::MemoryState_Shared | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted,
|
||||
KMemoryState_Shared = ams::svc::MemoryState_Shared | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped,
|
||||
|
||||
/* KMemoryState_Alias was removed after 1.0.0. */
|
||||
|
||||
@@ -82,7 +85,7 @@ namespace ams::kern {
|
||||
KMemoryState_Stack = ams::svc::MemoryState_Stack | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap
|
||||
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||
|
||||
KMemoryState_ThreadLocal = ams::svc::MemoryState_ThreadLocal | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted,
|
||||
KMemoryState_ThreadLocal = ams::svc::MemoryState_ThreadLocal | KMemoryState_FlagMapped | KMemoryState_FlagLinearMapped,
|
||||
|
||||
KMemoryState_Transfered = ams::svc::MemoryState_Transfered | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanChangeAttribute
|
||||
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||
@@ -90,7 +93,7 @@ namespace ams::kern {
|
||||
KMemoryState_SharedTransfered = ams::svc::MemoryState_SharedTransfered | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap
|
||||
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||
|
||||
KMemoryState_SharedCode = ams::svc::MemoryState_SharedCode | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted
|
||||
KMemoryState_SharedCode = ams::svc::MemoryState_SharedCode | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped
|
||||
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||
|
||||
KMemoryState_Inaccessible = ams::svc::MemoryState_Inaccessible,
|
||||
@@ -103,36 +106,41 @@ namespace ams::kern {
|
||||
|
||||
KMemoryState_Kernel = ams::svc::MemoryState_Kernel | KMemoryState_FlagMapped,
|
||||
|
||||
KMemoryState_GeneratedCode = ams::svc::MemoryState_GeneratedCode | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDebug,
|
||||
KMemoryState_CodeOut = ams::svc::MemoryState_CodeOut | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted,
|
||||
KMemoryState_GeneratedCode = ams::svc::MemoryState_GeneratedCode | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDebug | KMemoryState_FlagLinearMapped,
|
||||
KMemoryState_CodeOut = ams::svc::MemoryState_CodeOut | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped,
|
||||
|
||||
KMemoryState_Coverage = ams::svc::MemoryState_Coverage | KMemoryState_FlagMapped,
|
||||
|
||||
KMemoryState_Insecure = ams::svc::MemoryState_Insecure | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanChangeAttribute
|
||||
| KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap
|
||||
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||
};
|
||||
|
||||
#if 1
|
||||
static_assert(KMemoryState_Free == 0x00000000);
|
||||
static_assert(KMemoryState_Io == 0x00002001);
|
||||
static_assert(KMemoryState_Io == 0x00182001);
|
||||
static_assert(KMemoryState_Static == 0x00042002);
|
||||
static_assert(KMemoryState_Code == 0x00DC7E03);
|
||||
static_assert(KMemoryState_CodeData == 0x03FEBD04);
|
||||
static_assert(KMemoryState_Normal == 0x037EBD05);
|
||||
static_assert(KMemoryState_Shared == 0x00402006);
|
||||
static_assert(KMemoryState_Code == 0x04DC7E03);
|
||||
static_assert(KMemoryState_CodeData == 0x07FEBD04);
|
||||
static_assert(KMemoryState_Normal == 0x077EBD05);
|
||||
static_assert(KMemoryState_Shared == 0x04402006);
|
||||
|
||||
static_assert(KMemoryState_AliasCode == 0x00DD7E08);
|
||||
static_assert(KMemoryState_AliasCodeData == 0x03FFBD09);
|
||||
static_assert(KMemoryState_Ipc == 0x005C3C0A);
|
||||
static_assert(KMemoryState_Stack == 0x005C3C0B);
|
||||
static_assert(KMemoryState_ThreadLocal == 0x0040200C);
|
||||
static_assert(KMemoryState_Transfered == 0x015C3C0D);
|
||||
static_assert(KMemoryState_SharedTransfered == 0x005C380E);
|
||||
static_assert(KMemoryState_SharedCode == 0x0040380F);
|
||||
static_assert(KMemoryState_AliasCode == 0x04DD7E08);
|
||||
static_assert(KMemoryState_AliasCodeData == 0x07FFBD09);
|
||||
static_assert(KMemoryState_Ipc == 0x045C3C0A);
|
||||
static_assert(KMemoryState_Stack == 0x045C3C0B);
|
||||
static_assert(KMemoryState_ThreadLocal == 0x0400200C);
|
||||
static_assert(KMemoryState_Transfered == 0x055C3C0D);
|
||||
static_assert(KMemoryState_SharedTransfered == 0x045C380E);
|
||||
static_assert(KMemoryState_SharedCode == 0x0440380F);
|
||||
static_assert(KMemoryState_Inaccessible == 0x00000010);
|
||||
static_assert(KMemoryState_NonSecureIpc == 0x005C3811);
|
||||
static_assert(KMemoryState_NonDeviceIpc == 0x004C2812);
|
||||
static_assert(KMemoryState_NonSecureIpc == 0x045C3811);
|
||||
static_assert(KMemoryState_NonDeviceIpc == 0x044C2812);
|
||||
static_assert(KMemoryState_Kernel == 0x00002013);
|
||||
static_assert(KMemoryState_GeneratedCode == 0x00402214);
|
||||
static_assert(KMemoryState_CodeOut == 0x00402015);
|
||||
static_assert(KMemoryState_GeneratedCode == 0x04402214);
|
||||
static_assert(KMemoryState_CodeOut == 0x04402015);
|
||||
static_assert(KMemoryState_Coverage == 0x00002016);
|
||||
static_assert(KMemoryState_Insecure == 0x05583817);
|
||||
#endif
|
||||
|
||||
enum KMemoryPermission : u8 {
|
||||
|
||||
@@ -50,9 +50,11 @@ namespace ams::kern {
|
||||
constexpr size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSizeMax;
|
||||
|
||||
/* NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x800. */
|
||||
constexpr size_t KernelPageBufferHeapSize = 0x3E0000;
|
||||
constexpr size_t KernelSlabHeapAdditionalSize = 0x148000;
|
||||
constexpr size_t KernelPageBufferAdditionalSize = 0x33C000;
|
||||
|
||||
constexpr size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize;
|
||||
constexpr size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize + KernelPageBufferHeapSize;
|
||||
|
||||
class KMemoryLayout {
|
||||
private:
|
||||
@@ -150,6 +152,8 @@ namespace ams::kern {
|
||||
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetKernelTraceBufferRegion() { return Dereference(GetVirtualLinearMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelTraceBuffer)); }
|
||||
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetSecureAppletMemoryRegion() { return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelSecureAppletMemory)); }
|
||||
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetVirtualLinearRegion(KVirtualAddress address) { return Dereference(FindLinear(address)); }
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG const KMemoryRegion &GetPhysicalLinearRegion(KPhysicalAddress address) { return Dereference(FindLinear(address)); }
|
||||
|
||||
@@ -187,7 +191,7 @@ namespace ams::kern {
|
||||
|
||||
static void InitializeLinearMemoryRegionTrees();
|
||||
|
||||
static size_t GetResourceRegionSizeForInit();
|
||||
static size_t GetResourceRegionSizeForInit(bool use_extra_resource);
|
||||
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel); }
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelCodeRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelCode); }
|
||||
@@ -209,6 +213,7 @@ namespace ams::kern {
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelBase); }
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelCodeRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelCode); }
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelSlabRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelSlab); }
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelSecureAppletMemoryRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelSecureAppletMemory); }
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelPageTableHeapRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelPtHeap); }
|
||||
static MESOSPHERE_NOINLINE_IF_DEBUG auto GetKernelInitPageTableRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelInitPt); }
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ namespace ams::kern {
|
||||
|
||||
NOINLINE KPhysicalAddress AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
|
||||
NOINLINE Result AllocateAndOpen(KPageGroup *out, size_t num_pages, u32 option);
|
||||
NOINLINE Result AllocateAndOpenForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern);
|
||||
NOINLINE Result AllocateForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern);
|
||||
|
||||
Pool GetPool(KPhysicalAddress address) const {
|
||||
return this->GetManager(address).GetPool();
|
||||
@@ -222,6 +222,22 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenFirst(KPhysicalAddress address, size_t num_pages) {
|
||||
/* Repeatedly open references until we've done so for all pages. */
|
||||
while (num_pages) {
|
||||
auto &manager = this->GetManager(address);
|
||||
const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address));
|
||||
|
||||
{
|
||||
KScopedLightLock lk(m_pool_locks[manager.GetPool()]);
|
||||
manager.OpenFirst(address, cur_pages);
|
||||
}
|
||||
|
||||
num_pages -= cur_pages;
|
||||
address += cur_pages * PageSize;
|
||||
}
|
||||
}
|
||||
|
||||
void Close(KPhysicalAddress address, size_t num_pages) {
|
||||
/* Repeatedly close references until we've done so for all pages. */
|
||||
while (num_pages) {
|
||||
|
||||
@@ -211,6 +211,8 @@ namespace ams::kern {
|
||||
static_assert(KMemoryRegionType_DramKernelPtHeap.GetValue() == (0x24E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
||||
static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() == (0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
||||
|
||||
constexpr inline const auto KMemoryRegionType_DramKernelSecureAppletMemory = KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 0).SetAttribute(KMemoryRegionAttr_LinearMapped);
|
||||
static_assert(KMemoryRegionType_DramKernelSecureAppletMemory.GetValue() == (0x18E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
||||
|
||||
constexpr inline const auto KMemoryRegionType_DramReservedEarly = KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
|
||||
static_assert(KMemoryRegionType_DramReservedEarly.GetValue() == (0x16 | KMemoryRegionAttr_NoUserMap));
|
||||
@@ -251,6 +253,9 @@ namespace ams::kern {
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug = KMemoryRegionType_Dram.DeriveSparse(2, 2, 1);
|
||||
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x52));
|
||||
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory = KMemoryRegionType_Dram.DeriveSparse(3, 1, 0);
|
||||
static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x62));
|
||||
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
|
||||
constexpr inline const auto KMemoryRegionType_VirtualDramUserPool = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
|
||||
@@ -327,6 +332,8 @@ namespace ams::kern {
|
||||
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
|
||||
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
|
||||
return KMemoryRegionType_VirtualDramKernelPtHeap;
|
||||
} else if (KMemoryRegionType_DramKernelSecureAppletMemory.IsAncestorOf(type_id)) {
|
||||
return KMemoryRegionType_VirtualDramKernelSecureAppletMemory;
|
||||
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
|
||||
return KMemoryRegionType_VirtualDramUnknownDebug;
|
||||
} else {
|
||||
|
||||
@@ -113,11 +113,12 @@ namespace ams::kern {
|
||||
static constexpr size_t MaxDepth = 4;
|
||||
private:
|
||||
u64 *m_bit_storages[MaxDepth];
|
||||
u64 *m_end_storages[MaxDepth];
|
||||
RandomBitGenerator m_rng;
|
||||
size_t m_num_bits;
|
||||
size_t m_used_depths;
|
||||
public:
|
||||
KPageBitmap() : m_bit_storages(), m_rng(), m_num_bits(), m_used_depths() { /* ... */ }
|
||||
KPageBitmap() : m_bit_storages(), m_end_storages(), m_rng(), m_num_bits(), m_used_depths() { /* ... */ }
|
||||
|
||||
constexpr size_t GetNumBits() const { return m_num_bits; }
|
||||
constexpr s32 GetHighestDepthIndex() const { return static_cast<s32>(m_used_depths) - 1; }
|
||||
@@ -135,6 +136,7 @@ namespace ams::kern {
|
||||
m_bit_storages[depth] = storage;
|
||||
size = util::AlignUp(size, BITSIZEOF(u64)) / BITSIZEOF(u64);
|
||||
storage += size;
|
||||
m_end_storages[depth] = storage;
|
||||
}
|
||||
|
||||
return storage;
|
||||
@@ -171,6 +173,45 @@ namespace ams::kern {
|
||||
return static_cast<ssize_t>(offset);
|
||||
}
|
||||
|
||||
ssize_t FindFreeRange(size_t count) {
|
||||
/* Check that it is possible to find a range. */
|
||||
const u64 * const storage_start = m_bit_storages[m_used_depths - 1];
|
||||
const u64 * const storage_end = m_end_storages[m_used_depths - 1];
|
||||
|
||||
/* If we don't have a storage to iterate (or want more blocks than fit in a single storage), we can't find a free range. */
|
||||
if (!(storage_start < storage_end && count <= BITSIZEOF(u64))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Walk the storages to select a random free range. */
|
||||
const size_t options_per_storage = std::max<size_t>(BITSIZEOF(u64) / count, 1);
|
||||
const size_t num_entries = std::max<size_t>(storage_end - storage_start, 1);
|
||||
|
||||
const u64 free_mask = (static_cast<u64>(1) << count) - 1;
|
||||
|
||||
size_t num_valid_options = 0;
|
||||
ssize_t chosen_offset = -1;
|
||||
for (size_t storage_index = 0; storage_index < num_entries; ++storage_index) {
|
||||
u64 storage = storage_start[storage_index];
|
||||
for (size_t option = 0; option < options_per_storage; ++option) {
|
||||
if ((storage & free_mask) == free_mask) {
|
||||
/* We've found a new valid option. */
|
||||
++num_valid_options;
|
||||
|
||||
/* Select the Kth valid option with probability 1/K. This leads to an overall uniform distribution. */
|
||||
if (num_valid_options == 1 || m_rng.GenerateRandom(num_valid_options) == 0) {
|
||||
/* This is our first option, so select it. */
|
||||
chosen_offset = storage_index * BITSIZEOF(u64) + option * count;
|
||||
}
|
||||
}
|
||||
storage >>= count;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the random offset we chose.*/
|
||||
return chosen_offset;
|
||||
}
|
||||
|
||||
void SetBit(size_t offset) {
|
||||
this->SetBit(this->GetHighestDepthIndex(), offset);
|
||||
m_num_bits++;
|
||||
|
||||
@@ -16,12 +16,33 @@
|
||||
#pragma once
|
||||
#include <mesosphere/kern_slab_helpers.hpp>
|
||||
#include <mesosphere/kern_k_memory_layout.hpp>
|
||||
#include <mesosphere/kern_k_dynamic_page_manager.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
class KPageBuffer : public KSlabAllocated<KPageBuffer> {
|
||||
class KDynamicPageManager;
|
||||
|
||||
class KPageBuffer;
|
||||
|
||||
class KPageBufferSlabHeap : protected impl::KSlabHeapImpl {
|
||||
public:
|
||||
static constexpr size_t BufferSize = PageSize;
|
||||
static constinit inline size_t s_buffer_count = 0;
|
||||
private:
|
||||
alignas(PageSize) u8 m_buffer[PageSize];
|
||||
size_t m_obj_size{};
|
||||
public:
|
||||
constexpr KPageBufferSlabHeap() = default;
|
||||
|
||||
/* See kern_init_slab_setup.cpp for definition. */
|
||||
void Initialize(KDynamicPageManager &allocator);
|
||||
|
||||
KPageBuffer *Allocate();
|
||||
void Free(KPageBuffer *pb);
|
||||
};
|
||||
|
||||
class KPageBuffer {
|
||||
private:
|
||||
u8 m_buffer[KPageBufferSlabHeap::BufferSize];
|
||||
public:
|
||||
KPageBuffer() {
|
||||
std::memset(m_buffer, 0, sizeof(m_buffer));
|
||||
@@ -39,8 +60,49 @@ namespace ams::kern {
|
||||
|
||||
return GetPointer<KPageBuffer>(virt_addr);
|
||||
}
|
||||
private:
|
||||
static constinit inline KPageBufferSlabHeap s_slab_heap;
|
||||
public:
|
||||
static void InitializeSlabHeap(KDynamicPageManager &allocator) {
|
||||
s_slab_heap.Initialize(allocator);
|
||||
}
|
||||
|
||||
static KPageBuffer *Allocate() {
|
||||
return s_slab_heap.Allocate();
|
||||
}
|
||||
|
||||
static void Free(KPageBuffer *obj) {
|
||||
s_slab_heap.Free(obj);
|
||||
}
|
||||
|
||||
template<size_t ExpectedSize>
|
||||
static ALWAYS_INLINE KPageBuffer *AllocateChecked() {
|
||||
/* Check that the allocation is valid. */
|
||||
MESOSPHERE_ABORT_UNLESS(sizeof(KPageBuffer) == ExpectedSize);
|
||||
|
||||
return Allocate();
|
||||
}
|
||||
|
||||
template<size_t ExpectedSize>
|
||||
static ALWAYS_INLINE void FreeChecked(KPageBuffer *obj) {
|
||||
/* Check that the free is valid. */
|
||||
MESOSPHERE_ABORT_UNLESS(sizeof(KPageBuffer) == ExpectedSize);
|
||||
|
||||
return Free(obj);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(KPageBuffer) == PageSize);
|
||||
static_assert(alignof(KPageBuffer) == PageSize);
|
||||
static_assert(sizeof(KPageBuffer) == KPageBufferSlabHeap::BufferSize);
|
||||
|
||||
ALWAYS_INLINE KPageBuffer *KPageBufferSlabHeap::Allocate() {
|
||||
KPageBuffer *pb = static_cast<KPageBuffer *>(KSlabHeapImpl::Allocate());
|
||||
if (AMS_LIKELY(pb != nullptr)) {
|
||||
std::construct_at(pb);
|
||||
}
|
||||
return pb;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void KPageBufferSlabHeap::Free(KPageBuffer *pb) {
|
||||
KSlabHeapImpl::Free(pb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -138,6 +138,7 @@ namespace ams::kern {
|
||||
|
||||
Result AddBlock(KPhysicalAddress addr, size_t num_pages);
|
||||
void Open() const;
|
||||
void OpenFirst() const;
|
||||
void Close() const;
|
||||
|
||||
size_t GetNumPages() const;
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace ams::kern {
|
||||
static_assert(sizeof(KPageProperties) == sizeof(u32));
|
||||
|
||||
class KResourceLimit;
|
||||
class KSystemResource;
|
||||
|
||||
class KPageTableBase {
|
||||
NON_COPYABLE(KPageTableBase);
|
||||
@@ -72,10 +73,12 @@ namespace ams::kern {
|
||||
|
||||
enum OperationType {
|
||||
OperationType_Map = 0,
|
||||
OperationType_MapGroup = 1,
|
||||
OperationType_Unmap = 2,
|
||||
OperationType_ChangePermissions = 3,
|
||||
OperationType_ChangePermissionsAndRefresh = 4,
|
||||
OperationType_MapFirst = 1,
|
||||
OperationType_MapGroup = 2,
|
||||
OperationType_Unmap = 3,
|
||||
OperationType_ChangePermissions = 4,
|
||||
OperationType_ChangePermissionsAndRefresh = 5,
|
||||
OperationType_Separate = 6,
|
||||
};
|
||||
|
||||
static constexpr size_t MaxPhysicalMapAlignment = 1_GB;
|
||||
@@ -162,6 +165,7 @@ namespace ams::kern {
|
||||
size_t m_max_heap_size;
|
||||
size_t m_mapped_physical_memory_size;
|
||||
size_t m_mapped_unsafe_physical_memory;
|
||||
size_t m_mapped_insecure_memory;
|
||||
size_t m_mapped_ipc_server_memory;
|
||||
mutable KLightLock m_general_lock;
|
||||
mutable KLightLock m_map_physical_memory_lock;
|
||||
@@ -188,8 +192,8 @@ namespace ams::kern {
|
||||
m_alias_region_end(Null<KProcessAddress>), m_stack_region_start(Null<KProcessAddress>), m_stack_region_end(Null<KProcessAddress>),
|
||||
m_kernel_map_region_start(Null<KProcessAddress>), m_kernel_map_region_end(Null<KProcessAddress>), m_alias_code_region_start(Null<KProcessAddress>),
|
||||
m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>),
|
||||
m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_ipc_server_memory(), m_general_lock(),
|
||||
m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
|
||||
m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(),
|
||||
m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
|
||||
m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(),
|
||||
m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(),
|
||||
m_heap_fill_value(), m_ipc_fill_value(), m_stack_fill_value()
|
||||
@@ -200,7 +204,7 @@ namespace ams::kern {
|
||||
explicit KPageTableBase() { /* ... */ }
|
||||
|
||||
NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end);
|
||||
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KResourceLimit *resource_limit);
|
||||
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit);
|
||||
|
||||
void Finalize();
|
||||
|
||||
@@ -362,6 +366,8 @@ namespace ams::kern {
|
||||
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size);
|
||||
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||
Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm);
|
||||
Result MapInsecureMemory(KProcessAddress address, size_t size);
|
||||
Result UnmapInsecureMemory(KProcessAddress address, size_t size);
|
||||
|
||||
Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
|
||||
R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start, region_num_pages, state, perm));
|
||||
@@ -392,8 +398,8 @@ namespace ams::kern {
|
||||
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size);
|
||||
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size);
|
||||
|
||||
Result LockForMapDeviceAddressSpace(KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned);
|
||||
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size);
|
||||
Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap);
|
||||
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap);
|
||||
|
||||
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size);
|
||||
Result UnlockForDeviceAddressSpacePartialMap(KProcessAddress address, size_t size);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <mesosphere/kern_k_wait_object.hpp>
|
||||
#include <mesosphere/kern_k_dynamic_resource_manager.hpp>
|
||||
#include <mesosphere/kern_k_page_table_manager.hpp>
|
||||
#include <mesosphere/kern_k_system_resource.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
@@ -64,8 +65,7 @@ namespace ams::kern {
|
||||
s32 m_ideal_core_id;
|
||||
void *m_attached_object;
|
||||
KResourceLimit *m_resource_limit;
|
||||
KVirtualAddress m_system_resource_address;
|
||||
size_t m_system_resource_num_pages;
|
||||
KSystemResource *m_system_resource;
|
||||
size_t m_memory_release_hint;
|
||||
State m_state;
|
||||
KLightLock m_state_lock;
|
||||
@@ -117,13 +117,6 @@ namespace ams::kern {
|
||||
util::Atomic<s64> m_num_ipc_messages;
|
||||
util::Atomic<s64> m_num_ipc_replies;
|
||||
util::Atomic<s64> m_num_ipc_receives;
|
||||
KDynamicPageManager m_dynamic_page_manager;
|
||||
KMemoryBlockSlabManager m_memory_block_slab_manager;
|
||||
KBlockInfoManager m_block_info_manager;
|
||||
KPageTableManager m_page_table_manager;
|
||||
KMemoryBlockSlabHeap m_memory_block_heap;
|
||||
KBlockInfoSlabHeap m_block_info_heap;
|
||||
KPageTableSlabHeap m_page_table_heap;
|
||||
private:
|
||||
Result Initialize(const ams::svc::CreateProcessParameter ¶ms);
|
||||
|
||||
@@ -284,12 +277,12 @@ namespace ams::kern {
|
||||
void IncrementRunningThreadCount();
|
||||
void DecrementRunningThreadCount();
|
||||
|
||||
size_t GetTotalSystemResourceSize() const { return m_system_resource_num_pages * PageSize; }
|
||||
size_t GetTotalSystemResourceSize() const {
|
||||
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->GetSize() : 0;
|
||||
}
|
||||
|
||||
size_t GetUsedSystemResourceSize() const {
|
||||
if (m_system_resource_num_pages == 0) {
|
||||
return 0;
|
||||
}
|
||||
return m_dynamic_page_manager.GetUsed() * PageSize;
|
||||
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->GetUsedSize() : 0;
|
||||
}
|
||||
|
||||
void SetRunningThread(s32 core, KThread *thread, u64 idle_count) {
|
||||
@@ -305,10 +298,11 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
const KDynamicPageManager &GetDynamicPageManager() const { return m_dynamic_page_manager; }
|
||||
const KMemoryBlockSlabManager &GetMemoryBlockSlabManager() const { return m_memory_block_slab_manager; }
|
||||
const KBlockInfoManager &GetBlockInfoManager() const { return m_block_info_manager; }
|
||||
const KPageTableManager &GetPageTableManager() const { return m_page_table_manager; }
|
||||
const KSystemResource &GetSystemResource() const { return *m_system_resource; }
|
||||
|
||||
const KMemoryBlockSlabManager &GetMemoryBlockSlabManager() const { return m_system_resource->GetMemoryBlockSlabManager(); }
|
||||
const KBlockInfoManager &GetBlockInfoManager() const { return m_system_resource->GetBlockInfoManager(); }
|
||||
const KPageTableManager &GetPageTableManager() const { return m_system_resource->GetPageTableManager(); }
|
||||
|
||||
constexpr KThread *GetRunningThread(s32 core) const { return m_running_threads[core]; }
|
||||
constexpr u64 GetRunningThreadIdleCount(s32 core) const { return m_running_thread_idle_counts[core]; }
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace ams::kern {
|
||||
static NOINLINE void OnThreadPriorityChanged(KThread *thread, s32 old_priority);
|
||||
static NOINLINE void OnThreadAffinityMaskChanged(KThread *thread, const KAffinityMask &old_affinity, s32 old_core);
|
||||
|
||||
static NOINLINE void RotateScheduledQueue(s32 priority, s32 core_id);
|
||||
static NOINLINE void RotateScheduledQueue(s32 core_id, s32 priority);
|
||||
|
||||
static NOINLINE void YieldWithoutCoreMigration();
|
||||
static NOINLINE void YieldWithCoreMigration();
|
||||
|
||||
@@ -29,7 +29,10 @@ namespace ams::kern {
|
||||
public:
|
||||
class SessionMappings {
|
||||
private:
|
||||
static constexpr size_t NumStaticMappings = 8;
|
||||
/* At most 15 buffers of each type (4-bit descriptor counts), for 45 total. */
|
||||
static constexpr size_t NumMappings = ((1ul << 4) - 1) * 3;
|
||||
static constexpr size_t NumStaticMappings = 8;
|
||||
static constexpr size_t NumDynamicMappings = NumMappings - NumStaticMappings;
|
||||
|
||||
class Mapping {
|
||||
private:
|
||||
@@ -50,16 +53,27 @@ namespace ams::kern {
|
||||
constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
||||
constexpr ALWAYS_INLINE KMemoryState GetMemoryState() const { return m_state; }
|
||||
};
|
||||
public:
|
||||
class DynamicMappings : public KSlabAllocated<DynamicMappings, true> {
|
||||
private:
|
||||
Mapping m_mappings[NumDynamicMappings];
|
||||
public:
|
||||
constexpr explicit DynamicMappings() : m_mappings() { /* ... */ }
|
||||
|
||||
constexpr ALWAYS_INLINE Mapping &Get(size_t idx) { return m_mappings[idx]; }
|
||||
constexpr ALWAYS_INLINE const Mapping &Get(size_t idx) const { return m_mappings[idx]; }
|
||||
};
|
||||
static_assert(sizeof(DynamicMappings) == sizeof(Mapping) * NumDynamicMappings);
|
||||
private:
|
||||
Mapping m_static_mappings[NumStaticMappings];
|
||||
Mapping *m_mappings;
|
||||
DynamicMappings *m_dynamic_mappings;
|
||||
u8 m_num_send;
|
||||
u8 m_num_recv;
|
||||
u8 m_num_exch;
|
||||
public:
|
||||
constexpr explicit SessionMappings(util::ConstantInitializeTag) : m_static_mappings(), m_mappings(), m_num_send(), m_num_recv(), m_num_exch() { /* ... */ }
|
||||
constexpr explicit SessionMappings(util::ConstantInitializeTag) : m_static_mappings(), m_dynamic_mappings(), m_num_send(), m_num_recv(), m_num_exch() { /* ... */ }
|
||||
|
||||
explicit SessionMappings() : m_mappings(nullptr), m_num_send(), m_num_recv(), m_num_exch() { /* ... */ }
|
||||
explicit SessionMappings() : m_dynamic_mappings(nullptr), m_num_send(), m_num_recv(), m_num_exch() { /* ... */ }
|
||||
|
||||
void Initialize() { /* ... */ }
|
||||
void Finalize();
|
||||
@@ -96,7 +110,7 @@ namespace ams::kern {
|
||||
if (index < NumStaticMappings) {
|
||||
return m_static_mappings[index];
|
||||
} else {
|
||||
return m_mappings[index - NumStaticMappings];
|
||||
return m_dynamic_mappings->Get(index - NumStaticMappings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +121,7 @@ namespace ams::kern {
|
||||
if (index < NumStaticMappings) {
|
||||
return m_static_mappings[index];
|
||||
} else {
|
||||
return m_mappings[index - NumStaticMappings];
|
||||
return m_dynamic_mappings->Get(index - NumStaticMappings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +132,7 @@ namespace ams::kern {
|
||||
if (index < NumStaticMappings) {
|
||||
return m_static_mappings[index];
|
||||
} else {
|
||||
return m_mappings[index - NumStaticMappings];
|
||||
return m_dynamic_mappings->Get(index - NumStaticMappings);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace ams::kern {
|
||||
bool m_is_initialized;
|
||||
public:
|
||||
explicit KSharedMemory()
|
||||
: m_page_group(std::addressof(Kernel::GetSystemBlockInfoManager())), m_resource_limit(nullptr), m_owner_process_id(std::numeric_limits<u64>::max()),
|
||||
: m_page_group(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer()), m_resource_limit(nullptr), m_owner_process_id(std::numeric_limits<u64>::max()),
|
||||
m_owner_perm(ams::svc::MemoryPermission_None), m_remote_perm(ams::svc::MemoryPermission_None), m_is_initialized(false)
|
||||
{
|
||||
/* ... */
|
||||
|
||||
@@ -25,7 +25,12 @@ namespace ams::kern {
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
class KResourceLimit;
|
||||
|
||||
class KSystemControlBase {
|
||||
public:
|
||||
/* This can be overridden as needed. */
|
||||
static constexpr size_t SecureAppletMemorySize = 0;
|
||||
protected:
|
||||
/* Nintendo uses std::mt19937_t for randomness. */
|
||||
/* To save space (and because mt19337_t isn't secure anyway), */
|
||||
@@ -83,6 +88,10 @@ namespace ams::kern {
|
||||
static size_t CalculateRequiredSecureMemorySize(size_t size, u32 pool);
|
||||
static Result AllocateSecureMemory(KVirtualAddress *out, size_t size, u32 pool);
|
||||
static void FreeSecureMemory(KVirtualAddress address, size_t size, u32 pool);
|
||||
|
||||
/* Insecure Memory. */
|
||||
static KResourceLimit *GetInsecureMemoryResourceLimit();
|
||||
static u32 GetInsecureMemoryPool();
|
||||
protected:
|
||||
template<typename F>
|
||||
static ALWAYS_INLINE u64 GenerateUniformRange(u64 min, u64 max, F f) {
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <mesosphere/kern_common.hpp>
|
||||
#include <mesosphere/kern_k_auto_object.hpp>
|
||||
#include <mesosphere/kern_slab_helpers.hpp>
|
||||
#include <mesosphere/kern_k_memory_manager.hpp>
|
||||
#include <mesosphere/kern_k_dynamic_resource_manager.hpp>
|
||||
#include <mesosphere/kern_k_page_table_manager.hpp>
|
||||
#include <mesosphere/kern_k_resource_limit.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
/* NOTE: Nintendo's implementation does not have the "is_secure_resource" field, and instead uses virtual IsSecureResource(). */
|
||||
|
||||
class KSystemResource : public KAutoObject {
|
||||
MESOSPHERE_AUTOOBJECT_TRAITS(KSystemResource, KAutoObject);
|
||||
private:
|
||||
KMemoryBlockSlabManager *m_p_memory_block_slab_manager{};
|
||||
KBlockInfoManager *m_p_block_info_manager{};
|
||||
KPageTableManager *m_p_page_table_manager{};
|
||||
bool m_is_secure_resource{false};
|
||||
public:
|
||||
explicit KSystemResource() : KAutoObject() { /* ... */ }
|
||||
|
||||
constexpr explicit KSystemResource(util::ConstantInitializeTag) : KAutoObject(util::ConstantInitialize) { /* ... */ }
|
||||
protected:
|
||||
ALWAYS_INLINE void SetSecureResource() { m_is_secure_resource = true; }
|
||||
public:
|
||||
virtual void Destroy() override { MESOSPHERE_PANIC("KSystemResource::Destroy() was called"); }
|
||||
|
||||
ALWAYS_INLINE bool IsSecureResource() const { return m_is_secure_resource; }
|
||||
|
||||
void SetManagers(KMemoryBlockSlabManager &mb, KBlockInfoManager &bi, KPageTableManager &pt) {
|
||||
MESOSPHERE_ASSERT(m_p_memory_block_slab_manager == nullptr);
|
||||
MESOSPHERE_ASSERT(m_p_block_info_manager == nullptr);
|
||||
MESOSPHERE_ASSERT(m_p_page_table_manager == nullptr);
|
||||
|
||||
m_p_memory_block_slab_manager = std::addressof(mb);
|
||||
m_p_block_info_manager = std::addressof(bi);
|
||||
m_p_page_table_manager = std::addressof(pt);
|
||||
}
|
||||
|
||||
const KMemoryBlockSlabManager &GetMemoryBlockSlabManager() const { return *m_p_memory_block_slab_manager; }
|
||||
const KBlockInfoManager &GetBlockInfoManager() const { return *m_p_block_info_manager; }
|
||||
const KPageTableManager &GetPageTableManager() const { return *m_p_page_table_manager; }
|
||||
|
||||
KMemoryBlockSlabManager &GetMemoryBlockSlabManager() { return *m_p_memory_block_slab_manager; }
|
||||
KBlockInfoManager &GetBlockInfoManager() { return *m_p_block_info_manager; }
|
||||
KPageTableManager &GetPageTableManager() { return *m_p_page_table_manager; }
|
||||
|
||||
KMemoryBlockSlabManager *GetMemoryBlockSlabManagerPointer() { return m_p_memory_block_slab_manager; }
|
||||
KBlockInfoManager *GetBlockInfoManagerPointer() { return m_p_block_info_manager; }
|
||||
KPageTableManager *GetPageTableManagerPointer() { return m_p_page_table_manager; }
|
||||
};
|
||||
|
||||
class KSecureSystemResource final : public KAutoObjectWithSlabHeap<KSecureSystemResource, KSystemResource> {
|
||||
private:
|
||||
bool m_is_initialized;
|
||||
KMemoryManager::Pool m_resource_pool;
|
||||
KDynamicPageManager m_dynamic_page_manager;
|
||||
KMemoryBlockSlabManager m_memory_block_slab_manager;
|
||||
KBlockInfoManager m_block_info_manager;
|
||||
KPageTableManager m_page_table_manager;
|
||||
KMemoryBlockSlabHeap m_memory_block_heap;
|
||||
KBlockInfoSlabHeap m_block_info_heap;
|
||||
KPageTableSlabHeap m_page_table_heap;
|
||||
KResourceLimit *m_resource_limit;
|
||||
KVirtualAddress m_resource_address;
|
||||
size_t m_resource_size;
|
||||
public:
|
||||
explicit KSecureSystemResource() : m_is_initialized(false), m_resource_limit(nullptr) {
|
||||
/* Mark ourselves as being a secure resource. */
|
||||
this->SetSecureResource();
|
||||
}
|
||||
|
||||
Result Initialize(size_t size, KResourceLimit *resource_limit, KMemoryManager::Pool pool);
|
||||
void Finalize();
|
||||
|
||||
bool IsInitialized() const { return m_is_initialized; }
|
||||
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
|
||||
|
||||
ALWAYS_INLINE size_t CalculateRequiredSecureMemorySize() const {
|
||||
return CalculateRequiredSecureMemorySize(m_resource_size, m_resource_pool);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE size_t GetSize() const { return m_resource_size; }
|
||||
ALWAYS_INLINE size_t GetUsedSize() const { return m_dynamic_page_manager.GetUsed() * PageSize; }
|
||||
|
||||
const KDynamicPageManager &GetDynamicPageManager() const { return m_dynamic_page_manager; }
|
||||
public:
|
||||
static size_t CalculateRequiredSecureMemorySize(size_t size, KMemoryManager::Pool pool);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -63,7 +63,7 @@ namespace ams::kern {
|
||||
static constexpr size_t ApplicationMemoryBlockSlabHeapSize = 20000;
|
||||
static constexpr size_t SystemMemoryBlockSlabHeapSize = 10000;
|
||||
static constexpr size_t BlockInfoSlabHeapSize = 4000;
|
||||
static constexpr size_t ReservedDynamicPageCount = 70;
|
||||
static constexpr size_t ReservedDynamicPageCount = 64;
|
||||
private:
|
||||
static State s_state;
|
||||
static KResourceLimit s_system_resource_limit;
|
||||
@@ -78,6 +78,8 @@ namespace ams::kern {
|
||||
static KMemoryBlockSlabManager s_sys_memory_block_manager;
|
||||
static KBlockInfoManager s_app_block_info_manager;
|
||||
static KBlockInfoManager s_sys_block_info_manager;
|
||||
static KSystemResource s_app_system_resource;
|
||||
static KSystemResource s_sys_system_resource;
|
||||
static KSupervisorPageTable s_supervisor_page_table;
|
||||
static KUnsafeMemory s_unsafe_memory;
|
||||
static KWorkerTaskManager s_worker_task_managers[KWorkerTaskManager::WorkerType_Count];
|
||||
@@ -129,28 +131,12 @@ namespace ams::kern {
|
||||
return s_memory_manager;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE KMemoryBlockSlabManager &GetApplicationMemoryBlockManager() {
|
||||
return s_app_memory_block_manager;
|
||||
static ALWAYS_INLINE KSystemResource &GetApplicationSystemResource() {
|
||||
return s_app_system_resource;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE KMemoryBlockSlabManager &GetSystemMemoryBlockManager() {
|
||||
return s_sys_memory_block_manager;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE KBlockInfoManager &GetApplicationBlockInfoManager() {
|
||||
return s_app_block_info_manager;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE KBlockInfoManager &GetSystemBlockInfoManager() {
|
||||
return s_sys_block_info_manager;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE KPageTableManager &GetApplicationPageTableManager() {
|
||||
return s_app_page_table_manager;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE KPageTableManager &GetSystemPageTableManager() {
|
||||
return s_sys_page_table_manager;
|
||||
static ALWAYS_INLINE KSystemResource &GetSystemSystemResource() {
|
||||
return s_sys_system_resource;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE KSupervisorPageTable &GetKernelPageTable() {
|
||||
|
||||
@@ -64,11 +64,13 @@ namespace ams::kern {
|
||||
static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); }
|
||||
};
|
||||
|
||||
template<typename Derived, typename Base, bool SupportDynamicExpansion = false> requires std::derived_from<Base, KAutoObjectWithList>
|
||||
class KAutoObjectWithSlabHeapAndContainer : public Base {
|
||||
template<typename Derived, typename Base, bool SupportDynamicExpansion> requires std::derived_from<Base, KAutoObject>
|
||||
class KAutoObjectWithSlabHeapBase : public Base {
|
||||
private:
|
||||
template<typename, typename, bool> friend class KAutoObjectWithSlabHeap;
|
||||
template<typename, typename, bool> friend class KAutoObjectWithSlabHeapAndContainer;
|
||||
private:
|
||||
static constinit inline KSlabHeap<Derived, SupportDynamicExpansion> s_slab_heap;
|
||||
static constinit inline KAutoObjectWithListContainer<Derived> s_container;
|
||||
private:
|
||||
static ALWAYS_INLINE Derived *Allocate() {
|
||||
return s_slab_heap.Allocate();
|
||||
@@ -77,12 +79,6 @@ namespace ams::kern {
|
||||
static ALWAYS_INLINE void Free(Derived *obj) {
|
||||
s_slab_heap.Free(obj);
|
||||
}
|
||||
public:
|
||||
class ListAccessor : public KAutoObjectWithListContainer<Derived>::ListAccessor {
|
||||
public:
|
||||
ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer<Derived>::ListAccessor(s_container) { /* ... */ }
|
||||
ALWAYS_INLINE ~ListAccessor() { /* ... */ }
|
||||
};
|
||||
private:
|
||||
static ALWAYS_INLINE bool IsInitialized(const Derived *obj) {
|
||||
if constexpr (requires { { obj->IsInitialized() } -> std::same_as<bool>; }) {
|
||||
@@ -100,9 +96,9 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
public:
|
||||
constexpr explicit KAutoObjectWithSlabHeapAndContainer(util::ConstantInitializeTag) : Base(util::ConstantInitialize) { /* ... */ }
|
||||
constexpr explicit KAutoObjectWithSlabHeapBase(util::ConstantInitializeTag) : Base(util::ConstantInitialize) { /* ... */ }
|
||||
|
||||
explicit KAutoObjectWithSlabHeapAndContainer() { /* ... */ }
|
||||
explicit KAutoObjectWithSlabHeapBase() { /* ... */ }
|
||||
|
||||
/* NOTE: IsInitialized() and GetPostDestroyArgument() are virtual functions declared in this class, */
|
||||
/* in Nintendo's kernel. We fully devirtualize them, as Destroy() is the only user of them. */
|
||||
@@ -110,14 +106,14 @@ namespace ams::kern {
|
||||
virtual void Destroy() override final {
|
||||
Derived * const derived = static_cast<Derived *>(this);
|
||||
|
||||
if (IsInitialized(derived)) {
|
||||
s_container.Unregister(derived);
|
||||
const uintptr_t arg = GetPostDestroyArgument(derived);
|
||||
if (KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::IsInitialized(derived)) {
|
||||
Derived::PreFinalize(derived);
|
||||
const uintptr_t arg = KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::GetPostDestroyArgument(derived);
|
||||
derived->Finalize();
|
||||
Free(derived);
|
||||
KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::Free(derived);
|
||||
Derived::PostDestroy(arg);
|
||||
} else {
|
||||
Free(derived);
|
||||
KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::Free(derived);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +123,6 @@ namespace ams::kern {
|
||||
public:
|
||||
static void InitializeSlabHeap(void *memory, size_t memory_size) {
|
||||
s_slab_heap.Initialize(memory, memory_size);
|
||||
s_container.Initialize();
|
||||
}
|
||||
|
||||
static Derived *Create() {
|
||||
@@ -150,10 +145,6 @@ namespace ams::kern {
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void Register(Derived *obj) {
|
||||
return s_container.Register(obj);
|
||||
}
|
||||
|
||||
static size_t GetObjectSize() { return s_slab_heap.GetObjectSize(); }
|
||||
static size_t GetSlabHeapSize() { return s_slab_heap.GetSlabHeapSize(); }
|
||||
static size_t GetPeakIndex() { return s_slab_heap.GetPeakIndex(); }
|
||||
@@ -162,4 +153,42 @@ namespace ams::kern {
|
||||
static size_t GetNumRemaining() { return s_slab_heap.GetNumRemaining(); }
|
||||
};
|
||||
|
||||
template<typename Derived, typename Base, bool SupportDynamicExpansion = false>
|
||||
class KAutoObjectWithSlabHeap : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> {
|
||||
public:
|
||||
constexpr explicit KAutoObjectWithSlabHeap(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>(util::ConstantInitialize) { /* ... */ }
|
||||
|
||||
explicit KAutoObjectWithSlabHeap() { /* ... */ }
|
||||
|
||||
static ALWAYS_INLINE void PreFinalize(Derived *) { /* ... */ }
|
||||
};
|
||||
|
||||
|
||||
template<typename Derived, typename Base, bool SupportDynamicExpansion = false> requires std::derived_from<Base, KAutoObjectWithList>
|
||||
class KAutoObjectWithSlabHeapAndContainer : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> {
|
||||
private:
|
||||
static constinit inline KAutoObjectWithListContainer<Derived> s_container;
|
||||
public:
|
||||
class ListAccessor : public KAutoObjectWithListContainer<Derived>::ListAccessor {
|
||||
public:
|
||||
ALWAYS_INLINE ListAccessor() : KAutoObjectWithListContainer<Derived>::ListAccessor(s_container) { /* ... */ }
|
||||
ALWAYS_INLINE ~ListAccessor() { /* ... */ }
|
||||
};
|
||||
public:
|
||||
constexpr explicit KAutoObjectWithSlabHeapAndContainer(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>(util::ConstantInitialize) { /* ... */ }
|
||||
|
||||
explicit KAutoObjectWithSlabHeapAndContainer() { /* ... */ }
|
||||
public:
|
||||
static void InitializeSlabHeap(void *memory, size_t memory_size) {
|
||||
KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion>::InitializeSlabHeap(memory, memory_size);
|
||||
s_container.Initialize();
|
||||
}
|
||||
|
||||
static void Register(Derived *obj) {
|
||||
return s_container.Register(obj);
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void PreFinalize(Derived *obj) { s_container.Unregister(obj); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,25 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
ALWAYS_INLINE ~KScopedCoreMigrationDisable() { GetCurrentThread().EnableCoreMigration(); }
|
||||
};
|
||||
|
||||
class KScopedCacheMaintenance {
|
||||
private:
|
||||
bool m_active;
|
||||
public:
|
||||
ALWAYS_INLINE KScopedCacheMaintenance() {
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
if (m_active = !GetCurrentThread().IsInCacheMaintenanceOperation(); m_active) {
|
||||
GetCurrentThread().SetInCacheMaintenanceOperation();
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE ~KScopedCacheMaintenance() {
|
||||
if (m_active) {
|
||||
GetCurrentThread().ClearInCacheMaintenanceOperation();
|
||||
}
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
}
|
||||
};
|
||||
|
||||
/* Nintendo registers a handler for a SGI on thread termination, but does not handle anything. */
|
||||
/* This is sufficient, because post-interrupt scheduling is all they really intend to occur. */
|
||||
class KThreadTerminationInterruptHandler : public KInterruptHandler {
|
||||
@@ -432,9 +451,7 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
|
||||
Result InvalidateDataCache(void *addr, size_t size) {
|
||||
/* Mark ourselves as in a cache maintenance operation, and prevent re-ordering. */
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
GetCurrentThread().SetInCacheMaintenanceOperation();
|
||||
ON_SCOPE_EXIT { GetCurrentThread().ClearInCacheMaintenanceOperation(); __asm__ __volatile__("" ::: "memory"); };
|
||||
KScopedCacheMaintenance cm;
|
||||
|
||||
const uintptr_t start = reinterpret_cast<uintptr_t>(addr);
|
||||
const uintptr_t end = start + size;
|
||||
@@ -460,9 +477,7 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
|
||||
Result StoreDataCache(const void *addr, size_t size) {
|
||||
/* Mark ourselves as in a cache maintenance operation, and prevent re-ordering. */
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
GetCurrentThread().SetInCacheMaintenanceOperation();
|
||||
ON_SCOPE_EXIT { GetCurrentThread().ClearInCacheMaintenanceOperation(); __asm__ __volatile__("" ::: "memory"); };
|
||||
KScopedCacheMaintenance cm;
|
||||
|
||||
const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize);
|
||||
const uintptr_t end = util::AlignUp( reinterpret_cast<uintptr_t>(addr) + size, DataCacheLineSize);
|
||||
@@ -472,9 +487,7 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
|
||||
Result FlushDataCache(const void *addr, size_t size) {
|
||||
/* Mark ourselves as in a cache maintenance operation, and prevent re-ordering. */
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
GetCurrentThread().SetInCacheMaintenanceOperation();
|
||||
ON_SCOPE_EXIT { GetCurrentThread().ClearInCacheMaintenanceOperation(); __asm__ __volatile__("" ::: "memory"); };
|
||||
KScopedCacheMaintenance cm;
|
||||
|
||||
const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize);
|
||||
const uintptr_t end = util::AlignUp( reinterpret_cast<uintptr_t>(addr) + size, DataCacheLineSize);
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace ams::kern::arch::arm64 {
|
||||
Result KPageTable::InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end) {
|
||||
/* Initialize basic fields. */
|
||||
m_asid = 0;
|
||||
m_manager = std::addressof(Kernel::GetSystemPageTableManager());
|
||||
m_manager = Kernel::GetSystemSystemResource().GetPageTableManagerPointer();
|
||||
|
||||
/* Allocate a page for ttbr. */
|
||||
/* NOTE: It is a postcondition of page table manager allocation that the page is all-zero. */
|
||||
@@ -207,7 +207,7 @@ namespace ams::kern::arch::arm64 {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KPageTable::InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager, KResourceLimit *resource_limit) {
|
||||
Result KPageTable::InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
||||
/* The input ID isn't actually used. */
|
||||
MESOSPHERE_UNUSED(id);
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace ams::kern::arch::arm64 {
|
||||
ON_RESULT_FAILURE { g_asid_manager.Release(m_asid); };
|
||||
|
||||
/* Set our manager. */
|
||||
m_manager = pt_manager;
|
||||
m_manager = system_resource->GetPageTableManagerPointer();
|
||||
|
||||
/* Allocate a new table, and set our ttbr value. */
|
||||
const KVirtualAddress new_table = m_manager->Allocate();
|
||||
@@ -228,7 +228,7 @@ namespace ams::kern::arch::arm64 {
|
||||
const size_t as_width = GetAddressSpaceWidth(as_type);
|
||||
const KProcessAddress as_start = 0;
|
||||
const KProcessAddress as_end = (1ul << as_width);
|
||||
R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, mem_block_slab_manager, block_info_manager, resource_limit));
|
||||
R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, system_resource, resource_limit));
|
||||
|
||||
/* Note that we've updated the table (since we created it). */
|
||||
this->NoteUpdated();
|
||||
@@ -348,7 +348,7 @@ namespace ams::kern::arch::arm64 {
|
||||
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize));
|
||||
MESOSPHERE_ASSERT(this->ContainsPages(virt_addr, num_pages));
|
||||
|
||||
if (operation == OperationType_Map) {
|
||||
if (operation == OperationType_Map || operation == OperationType_MapFirst) {
|
||||
MESOSPHERE_ABORT_UNLESS(is_pa_valid);
|
||||
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize));
|
||||
} else {
|
||||
@@ -357,12 +357,26 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
if (operation == OperationType_Unmap) {
|
||||
R_RETURN(this->Unmap(virt_addr, num_pages, page_list, false, reuse_ll));
|
||||
} else if (operation == OperationType_Separate) {
|
||||
const size_t size = num_pages * PageSize;
|
||||
R_TRY(this->SeparatePages(virt_addr, std::min(util::GetAlignment(GetInteger(virt_addr)), size), page_list, reuse_ll));
|
||||
ON_RESULT_FAILURE { this->MergePages(virt_addr, page_list); };
|
||||
|
||||
if (num_pages > 1) {
|
||||
const auto end_page = virt_addr + size;
|
||||
const auto last_page = end_page - PageSize;
|
||||
|
||||
R_TRY(this->SeparatePages(last_page, std::min(util::GetAlignment(GetInteger(end_page)), size), page_list, reuse_ll));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
auto entry_template = this->GetEntryTemplate(properties);
|
||||
|
||||
switch (operation) {
|
||||
case OperationType_Map:
|
||||
R_RETURN(this->MapContiguous(virt_addr, phys_addr, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, page_list, reuse_ll));
|
||||
case OperationType_MapFirst:
|
||||
R_RETURN(this->MapContiguous(virt_addr, phys_addr, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, operation != OperationType_MapFirst, page_list, reuse_ll));
|
||||
case OperationType_ChangePermissions:
|
||||
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, page_list, reuse_ll));
|
||||
case OperationType_ChangePermissionsAndRefresh:
|
||||
@@ -740,7 +754,7 @@ namespace ams::kern::arch::arm64 {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KPageTable::MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll) {
|
||||
Result KPageTable::MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll) {
|
||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
/* Cache initial addresses for use on cleanup. */
|
||||
@@ -811,7 +825,11 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
/* Open references to the pages, if we should. */
|
||||
if (IsHeapPhysicalAddress(orig_phys_addr)) {
|
||||
Kernel::GetMemoryManager().Open(orig_phys_addr, num_pages);
|
||||
if (not_first) {
|
||||
Kernel::GetMemoryManager().Open(orig_phys_addr, num_pages);
|
||||
} else {
|
||||
Kernel::GetMemoryManager().OpenFirst(orig_phys_addr, num_pages);
|
||||
}
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
|
||||
@@ -86,9 +86,10 @@ _ZN3ams4kern3svc14RestoreContextEm:
|
||||
/* Get our exception flags. */
|
||||
ldrb w9, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)]
|
||||
|
||||
/* Clear in-svc and needs-fpu-restore flags. */
|
||||
/* Clear in-svc, in-user-exception, and needs-fpu-restore flags. */
|
||||
and w10, w9, #(~(THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED))
|
||||
and w10, w10, #(~(THREAD_EXCEPTION_FLAG_IS_CALLING_SVC))
|
||||
and w10, w10, #(~(THREAD_EXCEPTION_FLAG_IS_IN_USERMODE_EXCEPTION_HANDLER))
|
||||
strb w10, [sp, #(EXCEPTION_CONTEXT_SIZE + THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS)]
|
||||
|
||||
/* If we don't need to restore the fpu, skip restoring it. */
|
||||
|
||||
@@ -651,11 +651,13 @@ namespace ams::kern::board::nintendo::nx {
|
||||
g_memory_controller_address = KMemoryLayout::GetDevicePhysicalAddress(KMemoryRegionType_MemoryController);
|
||||
|
||||
/* Allocate a page to use as a reserved/no device table. */
|
||||
const KVirtualAddress table_virt_addr = Kernel::GetSystemPageTableManager().Allocate();
|
||||
auto &ptm = Kernel::GetSystemSystemResource().GetPageTableManager();
|
||||
|
||||
const KVirtualAddress table_virt_addr = ptm.Allocate();
|
||||
MESOSPHERE_ABORT_UNLESS(table_virt_addr != Null<KVirtualAddress>);
|
||||
const KPhysicalAddress table_phys_addr = GetPageTablePhysicalAddress(table_virt_addr);
|
||||
MESOSPHERE_ASSERT(IsValidPhysicalAddress(table_phys_addr));
|
||||
Kernel::GetSystemPageTableManager().Open(table_virt_addr, 1);
|
||||
ptm.Open(table_virt_addr, 1);
|
||||
|
||||
/* Save the page. Note that it is a pre-condition that the page is cleared, when allocated from the system page table manager. */
|
||||
/* NOTE: Nintendo does not check the result of StoreDataCache. */
|
||||
@@ -779,7 +781,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
const size_t end_index = (space_address + space_size - 1) / DeviceRegionSize;
|
||||
|
||||
/* Get the page table manager. */
|
||||
auto &ptm = Kernel::GetSystemPageTableManager();
|
||||
auto &ptm = Kernel::GetSystemSystemResource().GetPageTableManager();
|
||||
|
||||
/* Clear the tables. */
|
||||
static_assert(TableCount == (1ul << DeviceVirtualAddressBits) / DeviceRegionSize);
|
||||
@@ -839,7 +841,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
void KDevicePageTable::Finalize() {
|
||||
/* Get the page table manager. */
|
||||
auto &ptm = Kernel::GetSystemPageTableManager();
|
||||
auto &ptm = Kernel::GetSystemSystemResource().GetPageTableManager();
|
||||
|
||||
/* Detach from all devices. */
|
||||
{
|
||||
@@ -1014,7 +1016,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
/* Get the memory manager and page table manager. */
|
||||
KMemoryManager &mm = Kernel::GetMemoryManager();
|
||||
KPageTableManager &ptm = Kernel::GetSystemPageTableManager();
|
||||
KPageTableManager &ptm = Kernel::GetSystemSystemResource().GetPageTableManager();
|
||||
|
||||
/* Cache permissions. */
|
||||
const bool read = (device_perm & ams::svc::MemoryPermission_Read) != 0;
|
||||
@@ -1116,6 +1118,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
}
|
||||
|
||||
Result KDevicePageTable::MapImpl(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) {
|
||||
|
||||
/* Ensure that the region we're mapping to is free. */
|
||||
R_UNLESS(this->IsFree(device_address, size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
@@ -1158,10 +1161,10 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
/* Get the memory manager and page table manager. */
|
||||
KMemoryManager &mm = Kernel::GetMemoryManager();
|
||||
KPageTableManager &ptm = Kernel::GetSystemPageTableManager();
|
||||
KPageTableManager &ptm = Kernel::GetSystemSystemResource().GetPageTableManager();
|
||||
|
||||
/* Make a page group for the pages we're closing. */
|
||||
KPageGroup pg(std::addressof(Kernel::GetSystemBlockInfoManager()));
|
||||
KPageGroup pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
||||
|
||||
/* Walk the directory. */
|
||||
u64 remaining = size;
|
||||
@@ -1414,11 +1417,15 @@ namespace ams::kern::board::nintendo::nx {
|
||||
return true;
|
||||
}
|
||||
|
||||
Result KDevicePageTable::Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) {
|
||||
Result KDevicePageTable::Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool is_io) {
|
||||
/* Validate address/size. */
|
||||
MESOSPHERE_ASSERT((device_address & ~DeviceVirtualAddressMask) == 0);
|
||||
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
|
||||
|
||||
/* IO is not supported on NX board. */
|
||||
MESOSPHERE_ASSERT(!is_io);
|
||||
MESOSPHERE_UNUSED(is_io);
|
||||
|
||||
/* Map the pages. */
|
||||
R_RETURN(this->MapImpl(page_table, process_address, size, device_address, device_perm, is_aligned));
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace ams::kern::board::nintendo::nx {
|
||||
constinit bool g_call_smc_on_panic;
|
||||
|
||||
/* Global variables for secure memory. */
|
||||
constexpr size_t SecureAppletMemorySize = 4_MB;
|
||||
constinit KSpinLock g_secure_applet_lock;
|
||||
constinit bool g_secure_applet_memory_used = false;
|
||||
constinit KVirtualAddress g_secure_applet_memory_address = Null<KVirtualAddress>;
|
||||
@@ -246,8 +245,8 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
Result AllocateSecureMemoryForApplet(KVirtualAddress *out, size_t size) {
|
||||
/* Verify that the size is valid. */
|
||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||
R_UNLESS(size <= SecureAppletMemorySize, svc::ResultOutOfMemory());
|
||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||
R_UNLESS(size <= KSystemControl::SecureAppletMemorySize, svc::ResultOutOfMemory());
|
||||
|
||||
/* Disable interrupts and acquire the secure applet lock. */
|
||||
KScopedInterruptDisable di;
|
||||
@@ -273,7 +272,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
/* Verify that the memory being freed is correct. */
|
||||
MESOSPHERE_ABORT_UNLESS(address == g_secure_applet_memory_address);
|
||||
MESOSPHERE_ABORT_UNLESS(size <= SecureAppletMemorySize);
|
||||
MESOSPHERE_ABORT_UNLESS(size <= KSystemControl::SecureAppletMemorySize);
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, PageSize));
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_used);
|
||||
|
||||
@@ -451,17 +450,11 @@ namespace ams::kern::board::nintendo::nx {
|
||||
/* Initialize the sleep manager. */
|
||||
KSleepManager::Initialize();
|
||||
|
||||
/* Reserve secure applet memory. */
|
||||
if (GetTargetFirmware() >= TargetFirmware_5_0_0) {
|
||||
MESOSPHERE_ABORT_UNLESS(g_secure_applet_memory_address == Null<KVirtualAddress>);
|
||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, SecureAppletMemorySize));
|
||||
/* Get the secure applet memory. */
|
||||
const auto &secure_applet_memory = KMemoryLayout::GetSecureAppletMemoryRegion();
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(secure_applet_memory.GetSize() == SecureAppletMemorySize);
|
||||
|
||||
constexpr auto SecureAppletAllocateOption = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
|
||||
const KPhysicalAddress secure_applet_memory_phys_addr = Kernel::GetMemoryManager().AllocateAndOpenContinuous(SecureAppletMemorySize / PageSize, 1, SecureAppletAllocateOption);
|
||||
MESOSPHERE_ABORT_UNLESS(secure_applet_memory_phys_addr != Null<KPhysicalAddress>);
|
||||
|
||||
g_secure_applet_memory_address = KMemoryLayout::GetLinearVirtualAddress(secure_applet_memory_phys_addr);
|
||||
}
|
||||
g_secure_applet_memory_address = secure_applet_memory.GetAddress();
|
||||
|
||||
/* Initialize KTrace (and potentially other init). */
|
||||
KSystemControlBase::InitializePhase2();
|
||||
|
||||
@@ -17,30 +17,34 @@
|
||||
|
||||
namespace ams::kern::init {
|
||||
|
||||
/* For macro convenience. */
|
||||
using KSessionRequestMappings = KSessionRequest::SessionMappings::DynamicMappings;
|
||||
|
||||
#define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS
|
||||
|
||||
#define FOREACH_SLAB_TYPE(HANDLER, ...) \
|
||||
HANDLER(KProcess, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
|
||||
HANDLER(KThread, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \
|
||||
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ## __VA_ARGS__) \
|
||||
HANDLER(KInterruptEvent, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \
|
||||
HANDLER(KInterruptEventTask, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \
|
||||
HANDLER(KPort, (SLAB_COUNT(KPort)), ## __VA_ARGS__) \
|
||||
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ## __VA_ARGS__) \
|
||||
HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ## __VA_ARGS__) \
|
||||
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ## __VA_ARGS__) \
|
||||
HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ## __VA_ARGS__) \
|
||||
HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ## __VA_ARGS__) \
|
||||
HANDLER(KSession, (SLAB_COUNT(KSession)), ## __VA_ARGS__) \
|
||||
HANDLER(KSessionRequest, (SLAB_COUNT(KSession) * 2), ## __VA_ARGS__) \
|
||||
HANDLER(KLightSession, (SLAB_COUNT(KLightSession)), ## __VA_ARGS__) \
|
||||
HANDLER(KThreadLocalPage, (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), ## __VA_ARGS__) \
|
||||
HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ## __VA_ARGS__) \
|
||||
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ## __VA_ARGS__) \
|
||||
HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
|
||||
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
|
||||
HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \
|
||||
HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__)
|
||||
HANDLER(KProcess, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
|
||||
HANDLER(KThread, (SLAB_COUNT(KThread)), ## __VA_ARGS__) \
|
||||
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ## __VA_ARGS__) \
|
||||
HANDLER(KInterruptEvent, (SLAB_COUNT(KInterruptEvent)), ## __VA_ARGS__) \
|
||||
HANDLER(KPort, (SLAB_COUNT(KPort)), ## __VA_ARGS__) \
|
||||
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ## __VA_ARGS__) \
|
||||
HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ## __VA_ARGS__) \
|
||||
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ## __VA_ARGS__) \
|
||||
HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ## __VA_ARGS__) \
|
||||
HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ## __VA_ARGS__) \
|
||||
HANDLER(KSession, (SLAB_COUNT(KSession)), ## __VA_ARGS__) \
|
||||
HANDLER(KSessionRequest, (SLAB_COUNT(KSession) * 2), ## __VA_ARGS__) \
|
||||
HANDLER(KLightSession, (SLAB_COUNT(KLightSession)), ## __VA_ARGS__) \
|
||||
HANDLER(KThreadLocalPage, (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), ## __VA_ARGS__) \
|
||||
HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ## __VA_ARGS__) \
|
||||
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ## __VA_ARGS__) \
|
||||
HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
|
||||
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
|
||||
HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \
|
||||
HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__) \
|
||||
HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
|
||||
HANDLER(KSessionRequestMappings, (SLAB_COUNT(KSessionRequestMappings)), ## __VA_ARGS__)
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -55,50 +59,55 @@ namespace ams::kern::init {
|
||||
#undef DEFINE_SLAB_TYPE_ENUM_MEMBER
|
||||
|
||||
/* Constexpr counts. */
|
||||
constexpr size_t SlabCountKProcess = 80;
|
||||
constexpr size_t SlabCountKThread = 800;
|
||||
constexpr size_t SlabCountKEvent = 900;
|
||||
constexpr size_t SlabCountKInterruptEvent = 100;
|
||||
constexpr size_t SlabCountKPort = 384;
|
||||
constexpr size_t SlabCountKSharedMemory = 80;
|
||||
constexpr size_t SlabCountKTransferMemory = 200;
|
||||
constexpr size_t SlabCountKCodeMemory = 10;
|
||||
constexpr size_t SlabCountKDeviceAddressSpace = 300;
|
||||
constexpr size_t SlabCountKSession = 1133;
|
||||
constexpr size_t SlabCountKLightSession = 100;
|
||||
constexpr size_t SlabCountKObjectName = 7;
|
||||
constexpr size_t SlabCountKResourceLimit = 5;
|
||||
constexpr size_t SlabCountKDebug = cpu::NumCores;
|
||||
constexpr size_t SlabCountKIoPool = 1;
|
||||
constexpr size_t SlabCountKIoRegion = 6;
|
||||
constexpr size_t SlabCountKProcess = 80;
|
||||
constexpr size_t SlabCountKThread = 800;
|
||||
constexpr size_t SlabCountKEvent = 900;
|
||||
constexpr size_t SlabCountKInterruptEvent = 100;
|
||||
constexpr size_t SlabCountKPort = 384;
|
||||
constexpr size_t SlabCountKSharedMemory = 80;
|
||||
constexpr size_t SlabCountKTransferMemory = 200;
|
||||
constexpr size_t SlabCountKCodeMemory = 10;
|
||||
constexpr size_t SlabCountKDeviceAddressSpace = 300;
|
||||
constexpr size_t SlabCountKSession = 1133;
|
||||
constexpr size_t SlabCountKLightSession = 100;
|
||||
constexpr size_t SlabCountKObjectName = 7;
|
||||
constexpr size_t SlabCountKResourceLimit = 5;
|
||||
constexpr size_t SlabCountKDebug = cpu::NumCores;
|
||||
constexpr size_t SlabCountKIoPool = 1;
|
||||
constexpr size_t SlabCountKIoRegion = 6;
|
||||
constexpr size_t SlabcountKSessionRequestMappings = 40;
|
||||
|
||||
constexpr size_t SlabCountExtraKThread = (1024 + 256 + 256) - SlabCountKThread;
|
||||
constexpr size_t SlabCountExtraKThread = (1024 + 256 + 256) - SlabCountKThread;
|
||||
|
||||
namespace test {
|
||||
|
||||
constexpr size_t RequiredSizeForExtraThreadCount = SlabCountExtraKThread * (sizeof(KThread) + (sizeof(KThreadLocalPage) / 8) + sizeof(KEventInfo));
|
||||
static_assert(RequiredSizeForExtraThreadCount <= KernelSlabHeapAdditionalSize);
|
||||
|
||||
static_assert(KernelPageBufferHeapSize == 2 * PageSize + (SlabCountKProcess + SlabCountKThread + (SlabCountKProcess + SlabCountKThread) / 8) * PageSize);
|
||||
static_assert(KernelPageBufferAdditionalSize == (SlabCountExtraKThread + (SlabCountExtraKThread / 8)) * PageSize);
|
||||
|
||||
}
|
||||
|
||||
/* Global to hold our resource counts. */
|
||||
constinit KSlabResourceCounts g_slab_resource_counts = {
|
||||
.num_KProcess = SlabCountKProcess,
|
||||
.num_KThread = SlabCountKThread,
|
||||
.num_KEvent = SlabCountKEvent,
|
||||
.num_KInterruptEvent = SlabCountKInterruptEvent,
|
||||
.num_KPort = SlabCountKPort,
|
||||
.num_KSharedMemory = SlabCountKSharedMemory,
|
||||
.num_KTransferMemory = SlabCountKTransferMemory,
|
||||
.num_KCodeMemory = SlabCountKCodeMemory,
|
||||
.num_KDeviceAddressSpace = SlabCountKDeviceAddressSpace,
|
||||
.num_KSession = SlabCountKSession,
|
||||
.num_KLightSession = SlabCountKLightSession,
|
||||
.num_KObjectName = SlabCountKObjectName,
|
||||
.num_KResourceLimit = SlabCountKResourceLimit,
|
||||
.num_KDebug = SlabCountKDebug,
|
||||
.num_KIoPool = SlabCountKIoPool,
|
||||
.num_KIoRegion = SlabCountKIoRegion,
|
||||
.num_KProcess = SlabCountKProcess,
|
||||
.num_KThread = SlabCountKThread,
|
||||
.num_KEvent = SlabCountKEvent,
|
||||
.num_KInterruptEvent = SlabCountKInterruptEvent,
|
||||
.num_KPort = SlabCountKPort,
|
||||
.num_KSharedMemory = SlabCountKSharedMemory,
|
||||
.num_KTransferMemory = SlabCountKTransferMemory,
|
||||
.num_KCodeMemory = SlabCountKCodeMemory,
|
||||
.num_KDeviceAddressSpace = SlabCountKDeviceAddressSpace,
|
||||
.num_KSession = SlabCountKSession,
|
||||
.num_KLightSession = SlabCountKLightSession,
|
||||
.num_KObjectName = SlabCountKObjectName,
|
||||
.num_KResourceLimit = SlabCountKResourceLimit,
|
||||
.num_KDebug = SlabCountKDebug,
|
||||
.num_KIoPool = SlabCountKIoPool,
|
||||
.num_KIoRegion = SlabCountKIoRegion,
|
||||
.num_KSessionRequestMappings = SlabcountKSessionRequestMappings,
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -131,7 +140,7 @@ namespace ams::kern::init {
|
||||
}
|
||||
|
||||
size_t CalculateSlabHeapGapSize() {
|
||||
constexpr size_t KernelSlabHeapGapSize = 2_MB - 296_KB;
|
||||
constexpr size_t KernelSlabHeapGapSize = 2_MB - 320_KB;
|
||||
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
|
||||
return KernelSlabHeapGapSize;
|
||||
}
|
||||
@@ -155,23 +164,6 @@ namespace ams::kern::init {
|
||||
return size;
|
||||
}
|
||||
|
||||
void InitializeKPageBufferSlabHeap() {
|
||||
const auto &counts = GetSlabResourceCounts();
|
||||
const size_t num_pages = counts.num_KProcess + counts.num_KThread + (counts.num_KProcess + counts.num_KThread) / 8;
|
||||
const size_t slab_size = num_pages * PageSize;
|
||||
|
||||
/* Reserve memory from the system resource limit. */
|
||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, slab_size));
|
||||
|
||||
/* Allocate memory for the slab. */
|
||||
constexpr auto AllocateOption = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
|
||||
const KPhysicalAddress slab_address = Kernel::GetMemoryManager().AllocateAndOpenContinuous(num_pages, 1, AllocateOption);
|
||||
MESOSPHERE_ABORT_UNLESS(slab_address != Null<KPhysicalAddress>);
|
||||
|
||||
/* Initialize the slabheap. */
|
||||
KPageBuffer::InitializeSlabHeap(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(slab_address)), slab_size);
|
||||
}
|
||||
|
||||
void InitializeSlabHeaps() {
|
||||
/* Get the slab region, since that's where we'll be working. */
|
||||
const KMemoryRegion &slab_region = KMemoryLayout::GetSlabRegion();
|
||||
@@ -240,4 +232,34 @@ namespace ams::kern::init {
|
||||
FreeUnusedSlabMemory(gap_start, gap_size + (slab_region.GetEndAddress() - GetInteger(address)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
void KPageBufferSlabHeap::Initialize(KDynamicPageManager &allocator) {
|
||||
/* Get slab resource counts. */
|
||||
const auto &counts = init::GetSlabResourceCounts();
|
||||
|
||||
/* If size is correct, account for thread local pages. */
|
||||
if (BufferSize == PageSize) {
|
||||
s_buffer_count += counts.num_KProcess + counts.num_KThread + (counts.num_KProcess + counts.num_KThread) / 8;
|
||||
}
|
||||
|
||||
/* Set our object size. */
|
||||
m_obj_size = BufferSize;
|
||||
|
||||
/* Initialize the base allocator. */
|
||||
KSlabHeapImpl::Initialize();
|
||||
|
||||
/* Allocate the desired page count. */
|
||||
for (size_t i = 0; i < s_buffer_count; ++i) {
|
||||
/* Allocate an appropriate buffer. */
|
||||
auto * const pb = (BufferSize <= PageSize) ? allocator.Allocate() : allocator.Allocate(BufferSize / PageSize);
|
||||
MESOSPHERE_ABORT_UNLESS(pb != nullptr);
|
||||
|
||||
/* Free to our slab. */
|
||||
KSlabHeapImpl::Free(pb);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -128,13 +128,13 @@ namespace ams::kern {
|
||||
KProcess *new_process = nullptr;
|
||||
{
|
||||
/* Make page groups to represent the data. */
|
||||
KPageGroup pg(std::addressof(Kernel::GetSystemBlockInfoManager()));
|
||||
KPageGroup workaround_pg(std::addressof(Kernel::GetSystemBlockInfoManager()));
|
||||
KPageGroup pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
||||
KPageGroup workaround_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
||||
|
||||
/* Populate the page group to represent the data. */
|
||||
{
|
||||
/* Allocate the previously unreserved pages. */
|
||||
KPageGroup unreserve_pg(std::addressof(Kernel::GetSystemBlockInfoManager()));
|
||||
KPageGroup unreserve_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
||||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(unreserve_pg), unreserved_size / PageSize, KMemoryManager::EncodeOption(dst_pool, KMemoryManager::Direction_FromFront)));
|
||||
|
||||
/* Add the previously reserved pages. */
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace ams::kern {
|
||||
s32 new_value;
|
||||
if (count <= 0) {
|
||||
if ((it != m_tree.end()) && (it->GetAddressArbiterKey() == addr)) {
|
||||
new_value = value - 2;
|
||||
new_value = value - 1;
|
||||
} else {
|
||||
new_value = value + 1;
|
||||
}
|
||||
@@ -132,7 +132,7 @@ namespace ams::kern {
|
||||
auto tmp_it = it;
|
||||
s32 tmp_num_waiters = 0;
|
||||
while ((++tmp_it != m_tree.end()) && (tmp_it->GetAddressArbiterKey() == addr)) {
|
||||
if ((tmp_num_waiters++) >= count) {
|
||||
if ((++tmp_num_waiters) >= count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,12 @@ namespace ams::kern {
|
||||
static_assert(ClassToken<KDeviceAddressSpace> == 0b10010001'00000000);
|
||||
static_assert(ClassToken<KSessionRequest> == 0b01100001'00000000);
|
||||
static_assert(ClassToken<KCodeMemory> == 0b10100001'00000000);
|
||||
static_assert(ClassToken<KIoPool> == 0b11000001'00000000);
|
||||
static_assert(ClassToken<KIoRegion> == 0b00001110'00000000);
|
||||
/* 0b00010110'00000000 */
|
||||
/* 0b00100110'00000000 */
|
||||
static_assert(ClassToken<KSystemResource> == 0b01000110'00000000);
|
||||
|
||||
|
||||
/* Ensure that the token hierarchy is correct. */
|
||||
|
||||
@@ -72,6 +78,10 @@ namespace ams::kern {
|
||||
static_assert(ClassToken<KDeviceAddressSpace> == ((0b10010001 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KSessionRequest> == ((0b01100001 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KCodeMemory> == ((0b10100001 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KIoPool> == ((0b11000001 << 8) | ClassToken<KAutoObject>));
|
||||
static_assert(ClassToken<KIoRegion> == ((0b00001110 << 8) | ClassToken<KAutoObject>));
|
||||
|
||||
static_assert(ClassToken<KSystemResource> == ((0b01000110 << 8) | ClassToken<KAutoObject>));
|
||||
|
||||
/* Ensure that the token hierarchy reflects the class hierarchy. */
|
||||
|
||||
@@ -100,6 +110,10 @@ namespace ams::kern {
|
||||
static_assert(std::is_final<KDeviceAddressSpace>::value && std::is_base_of<KAutoObject, KDeviceAddressSpace>::value);
|
||||
static_assert(std::is_final<KSessionRequest>::value && std::is_base_of<KAutoObject, KSessionRequest>::value);
|
||||
static_assert(std::is_final<KCodeMemory>::value && std::is_base_of<KAutoObject, KCodeMemory>::value);
|
||||
static_assert(std::is_final<KIoPool>::value && std::is_base_of<KAutoObject, KIoPool>::value);
|
||||
static_assert(std::is_final<KIoRegion>::value && std::is_base_of<KAutoObject, KIoRegion>::value);
|
||||
|
||||
static_assert(std::is_base_of<KAutoObject, KSystemResource>::value);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -61,10 +61,21 @@ namespace ams::kern {
|
||||
R_RETURN(m_table.Detach(device_name));
|
||||
}
|
||||
|
||||
Result KDeviceAddressSpace::Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) {
|
||||
Result KDeviceAddressSpace::Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, u32 option, bool is_aligned) {
|
||||
/* Check that the address falls within the space. */
|
||||
R_UNLESS((m_space_address <= device_address && device_address + size - 1 <= m_space_address + m_space_size - 1), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Decode the option. */
|
||||
const util::BitPack32 option_pack = { option };
|
||||
const auto device_perm = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Permission>();
|
||||
const auto flags = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Flags>();
|
||||
const auto reserved = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Reserved>();
|
||||
|
||||
/* Validate the option. */
|
||||
/* TODO: It is likely that this check for flags == none is only on NX board. */
|
||||
R_UNLESS(flags == ams::svc::MapDeviceAddressSpaceFlag_None, svc::ResultInvalidEnumValue());
|
||||
R_UNLESS(reserved == 0, svc::ResultInvalidEnumValue());
|
||||
|
||||
/* Lock the address space. */
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
@@ -72,15 +83,21 @@ namespace ams::kern {
|
||||
KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock();
|
||||
|
||||
/* Lock the pages. */
|
||||
R_TRY(page_table->LockForMapDeviceAddressSpace(process_address, size, ConvertToKMemoryPermission(device_perm), is_aligned));
|
||||
bool is_io{};
|
||||
R_TRY(page_table->LockForMapDeviceAddressSpace(std::addressof(is_io), process_address, size, ConvertToKMemoryPermission(device_perm), is_aligned, true));
|
||||
|
||||
/* Ensure that if we fail, we don't keep unmapped pages locked. */
|
||||
ON_RESULT_FAILURE { MESOSPHERE_R_ABORT_UNLESS(page_table->UnlockForDeviceAddressSpace(process_address, size)); };
|
||||
|
||||
/* Check that the io status is allowable. */
|
||||
if (is_io) {
|
||||
R_UNLESS((flags & ams::svc::MapDeviceAddressSpaceFlag_NotIoRegister) == 0, svc::ResultInvalidCombination());
|
||||
}
|
||||
|
||||
/* Map the pages. */
|
||||
{
|
||||
/* Perform the mapping. */
|
||||
R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm, is_aligned));
|
||||
R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm, is_aligned, is_io));
|
||||
|
||||
/* Ensure that we unmap the pages if we fail to update the protections. */
|
||||
/* NOTE: Nintendo does not check the result of this unmap call. */
|
||||
@@ -105,7 +122,7 @@ namespace ams::kern {
|
||||
KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock();
|
||||
|
||||
/* Lock the pages. */
|
||||
R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size));
|
||||
R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size, true));
|
||||
|
||||
/* Unmap the pages. */
|
||||
{
|
||||
|
||||
@@ -332,7 +332,6 @@ namespace ams::kern::KDumpObject {
|
||||
MESOSPHERE_RELEASE_LOG(#__OBJECT__ "\n"); \
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%3zu Peak=%3zu Max=%3zu\n", __OBJECT__::GetSlabHeapSize() - __OBJECT__::GetNumRemaining(), __OBJECT__::GetPeakIndex(), __OBJECT__::GetSlabHeapSize())
|
||||
|
||||
DUMP_KSLABOBJ(KPageBuffer);
|
||||
DUMP_KSLABOBJ(KEvent);
|
||||
DUMP_KSLABOBJ(KInterruptEvent);
|
||||
DUMP_KSLABOBJ(KProcess);
|
||||
@@ -362,24 +361,24 @@ namespace ams::kern::KDumpObject {
|
||||
/* Memory block slabs. */
|
||||
{
|
||||
MESOSPHERE_RELEASE_LOG("App Memory Block\n");
|
||||
auto &app = Kernel::GetApplicationMemoryBlockManager();
|
||||
auto &app = Kernel::GetApplicationSystemResource().GetMemoryBlockSlabManager();
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", app.GetUsed(), app.GetPeak(), app.GetCount());
|
||||
MESOSPHERE_RELEASE_LOG("Sys Memory Block\n");
|
||||
auto &sys = Kernel::GetSystemMemoryBlockManager();
|
||||
auto &sys = Kernel::GetSystemSystemResource().GetMemoryBlockSlabManager();
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", sys.GetUsed(), sys.GetPeak(), sys.GetCount());
|
||||
}
|
||||
|
||||
/* KBlockInfo slab. */
|
||||
{
|
||||
MESOSPHERE_RELEASE_LOG("KBlockInfo\n");
|
||||
auto &manager = Kernel::GetSystemBlockInfoManager();
|
||||
auto &manager = Kernel::GetSystemSystemResource().GetBlockInfoManager();
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", manager.GetUsed(), manager.GetPeak(), manager.GetCount());
|
||||
}
|
||||
|
||||
/* Page Table slab. */
|
||||
{
|
||||
MESOSPHERE_RELEASE_LOG("Page Table\n");
|
||||
auto &manager = Kernel::GetSystemPageTableManager();
|
||||
auto &manager = Kernel::GetSystemSystemResource().GetPageTableManager();
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", manager.GetUsed(), manager.GetPeak(), manager.GetCount());
|
||||
}
|
||||
}
|
||||
@@ -425,15 +424,17 @@ namespace ams::kern::KDumpObject {
|
||||
process_pts += pts;
|
||||
|
||||
MESOSPHERE_RELEASE_LOG("%-12s: PID=%3lu Thread %4d / Event %4d / PageTable %5zu\n", process->GetName(), process->GetId(), threads, events, pts);
|
||||
if (process->GetTotalSystemResourceSize() != 0) {
|
||||
if (const auto &system_resource = process->GetSystemResource(); system_resource.IsSecureResource()) {
|
||||
const auto &secure_resource = static_cast<const KSecureSystemResource &>(system_resource);
|
||||
|
||||
MESOSPHERE_RELEASE_LOG(" System Resource\n");
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetDynamicPageManager().GetUsed(), process->GetDynamicPageManager().GetPeak(), process->GetDynamicPageManager().GetCount());
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetDynamicPageManager().GetUsed(), secure_resource.GetDynamicPageManager().GetPeak(), secure_resource.GetDynamicPageManager().GetCount());
|
||||
MESOSPHERE_RELEASE_LOG(" Memory Block\n");
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetMemoryBlockSlabManager().GetUsed(), process->GetMemoryBlockSlabManager().GetPeak(), process->GetMemoryBlockSlabManager().GetCount());
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetMemoryBlockSlabManager().GetUsed(), secure_resource.GetMemoryBlockSlabManager().GetPeak(), secure_resource.GetMemoryBlockSlabManager().GetCount());
|
||||
MESOSPHERE_RELEASE_LOG(" Page Table\n");
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetPageTableManager().GetUsed(), process->GetPageTableManager().GetPeak(), process->GetPageTableManager().GetCount());
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetPageTableManager().GetUsed(), secure_resource.GetPageTableManager().GetPeak(), secure_resource.GetPageTableManager().GetCount());
|
||||
MESOSPHERE_RELEASE_LOG(" Block Info\n");
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", process->GetBlockInfoManager().GetUsed(), process->GetBlockInfoManager().GetPeak(), process->GetBlockInfoManager().GetCount());
|
||||
MESOSPHERE_RELEASE_LOG(" Cur=%6zu Peak=%6zu Max=%6zu\n", secure_resource.GetBlockInfoManager().GetUsed(), secure_resource.GetBlockInfoManager().GetPeak(), secure_resource.GetBlockInfoManager().GetCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,13 +17,6 @@
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit KLightLock g_interrupt_event_lock;
|
||||
constinit KInterruptEventTask *g_interrupt_event_task_table[KInterruptController::NumInterrupts] = {};
|
||||
|
||||
}
|
||||
|
||||
Result KInterruptEvent::Initialize(int32_t interrupt_name, ams::svc::InterruptType type) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
@@ -40,8 +33,8 @@ namespace ams::kern {
|
||||
/* Initialize readable event base. */
|
||||
KReadableEvent::Initialize(nullptr);
|
||||
|
||||
/* Try to register the task. */
|
||||
R_TRY(KInterruptEventTask::Register(m_interrupt_id, m_core_id, type == ams::svc::InterruptType_Level, this));
|
||||
/* Bind ourselves as the handler for our interrupt id. */
|
||||
R_TRY(Kernel::GetInterruptManager().BindHandler(this, m_interrupt_id, m_core_id, KInterruptController::PriorityLevel_High, true, type == ams::svc::InterruptType_Level));
|
||||
|
||||
/* Mark initialized. */
|
||||
m_is_initialized = true;
|
||||
@@ -51,7 +44,11 @@ namespace ams::kern {
|
||||
void KInterruptEvent::Finalize() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
g_interrupt_event_task_table[m_interrupt_id]->Unregister(m_interrupt_id, m_core_id);
|
||||
/* Unbind ourselves as the handler for our interrupt id. */
|
||||
Kernel::GetInterruptManager().UnbindHandler(m_interrupt_id, m_core_id);
|
||||
|
||||
/* Synchronize the unbind on all cores, before proceeding. */
|
||||
KDpcManager::Sync();
|
||||
|
||||
/* Perform inherited finalization. */
|
||||
KReadableEvent::Finalize();
|
||||
@@ -72,79 +69,19 @@ namespace ams::kern {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KInterruptEventTask::Register(s32 interrupt_id, s32 core_id, bool level, KInterruptEvent *event) {
|
||||
/* Lock the task table. */
|
||||
KScopedLightLock lk(g_interrupt_event_lock);
|
||||
|
||||
/* Get a task for the id. */
|
||||
bool allocated = false;
|
||||
KInterruptEventTask *task = g_interrupt_event_task_table[interrupt_id];
|
||||
if (task != nullptr) {
|
||||
/* Check that there's not already an event for this task. */
|
||||
R_UNLESS(task->m_event == nullptr, svc::ResultBusy());
|
||||
} else {
|
||||
/* Allocate a new task. */
|
||||
task = KInterruptEventTask::Allocate();
|
||||
R_UNLESS(task != nullptr, svc::ResultOutOfResource());
|
||||
|
||||
allocated = true;
|
||||
}
|
||||
|
||||
/* Ensure that the task is cleaned up if anything goes wrong. */
|
||||
ON_RESULT_FAILURE { if (allocated) { KInterruptEventTask::Free(task); } };
|
||||
|
||||
/* Register/bind the interrupt task. */
|
||||
{
|
||||
/* Lock the scheduler. */
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
/* Bind the interrupt handler. */
|
||||
R_TRY(Kernel::GetInterruptManager().BindHandler(task, interrupt_id, core_id, KInterruptController::PriorityLevel_High, true, level));
|
||||
|
||||
/* Set the event. */
|
||||
task->m_event = event;
|
||||
}
|
||||
|
||||
/* If we allocated, set the event in the table. */
|
||||
if (allocated) {
|
||||
g_interrupt_event_task_table[interrupt_id] = task;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void KInterruptEventTask::Unregister(s32 interrupt_id, s32 core_id) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Lock the task table. */
|
||||
KScopedLightLock lk(g_interrupt_event_lock);
|
||||
|
||||
/* Lock the scheduler. */
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
/* Ensure we can unregister. */
|
||||
MESOSPHERE_ABORT_UNLESS(g_interrupt_event_task_table[interrupt_id] == this);
|
||||
MESOSPHERE_ABORT_UNLESS(m_event != nullptr);
|
||||
|
||||
/* Unbind the interrupt. */
|
||||
m_event = nullptr;
|
||||
Kernel::GetInterruptManager().UnbindHandler(interrupt_id, core_id);
|
||||
}
|
||||
|
||||
KInterruptTask *KInterruptEventTask::OnInterrupt(s32 interrupt_id) {
|
||||
KInterruptTask *KInterruptEvent::OnInterrupt(s32 interrupt_id) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
MESOSPHERE_UNUSED(interrupt_id);
|
||||
return this;
|
||||
}
|
||||
|
||||
void KInterruptEventTask::DoTask() {
|
||||
void KInterruptEvent::DoTask() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
/* Lock the scheduler. */
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
if (m_event != nullptr) {
|
||||
m_event->Signal();
|
||||
}
|
||||
/* Signal. */
|
||||
this->Signal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,11 +126,8 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
size_t KMemoryLayout::GetResourceRegionSizeForInit() {
|
||||
/* Calculate resource region size based on whether we allow extra threads. */
|
||||
const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit();
|
||||
|
||||
return KernelResourceSize + (use_extra_resources ? KernelSlabHeapAdditionalSize : 0);
|
||||
size_t KMemoryLayout::GetResourceRegionSizeForInit(bool use_extra_resource) {
|
||||
return KernelResourceSize + KSystemControl::SecureAppletMemorySize + (use_extra_resource ? KernelSlabHeapAdditionalSize + KernelPageBufferAdditionalSize : 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ namespace ams::kern {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KMemoryManager::AllocateAndOpenForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern) {
|
||||
Result KMemoryManager::AllocateForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern) {
|
||||
MESOSPHERE_ASSERT(out != nullptr);
|
||||
MESOSPHERE_ASSERT(out->GetNumPages() == 0);
|
||||
|
||||
@@ -330,24 +330,6 @@ namespace ams::kern {
|
||||
|
||||
/* Set whether we should optimize. */
|
||||
optimized = has_optimized && is_optimized;
|
||||
|
||||
/* Open the first reference to the pages. */
|
||||
for (const auto &block : *out) {
|
||||
KPhysicalAddress cur_address = block.GetAddress();
|
||||
size_t remaining_pages = block.GetNumPages();
|
||||
while (remaining_pages > 0) {
|
||||
/* Get the manager for the current address. */
|
||||
auto &manager = this->GetManager(cur_address);
|
||||
|
||||
/* Process part or all of the block. */
|
||||
const size_t cur_pages = std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address));
|
||||
manager.OpenFirst(cur_address, cur_pages);
|
||||
|
||||
/* Advance. */
|
||||
cur_address += cur_pages * PageSize;
|
||||
remaining_pages -= cur_pages;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform optimized memory tracking, if we should. */
|
||||
|
||||
@@ -92,6 +92,14 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
void KPageGroup::OpenFirst() const {
|
||||
auto &mm = Kernel::GetMemoryManager();
|
||||
|
||||
for (const auto &it : *this) {
|
||||
mm.OpenFirst(it.GetAddress(), it.GetNumPages());
|
||||
}
|
||||
}
|
||||
|
||||
void KPageGroup::Close() const {
|
||||
auto &mm = Kernel::GetMemoryManager();
|
||||
|
||||
|
||||
@@ -103,10 +103,11 @@ namespace ams::kern {
|
||||
m_max_heap_size = 0;
|
||||
m_mapped_physical_memory_size = 0;
|
||||
m_mapped_unsafe_physical_memory = 0;
|
||||
m_mapped_insecure_memory = 0;
|
||||
m_mapped_ipc_server_memory = 0;
|
||||
|
||||
m_memory_block_slab_manager = std::addressof(Kernel::GetSystemMemoryBlockManager());
|
||||
m_block_info_manager = std::addressof(Kernel::GetSystemBlockInfoManager());
|
||||
m_memory_block_slab_manager = Kernel::GetSystemSystemResource().GetMemoryBlockSlabManagerPointer();
|
||||
m_block_info_manager = Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer();
|
||||
m_resource_limit = std::addressof(Kernel::GetSystemResourceLimit());
|
||||
|
||||
m_allocate_option = KMemoryManager::EncodeOption(KMemoryManager::Pool_System, KMemoryManager::Direction_FromFront);
|
||||
@@ -124,7 +125,7 @@ namespace ams::kern {
|
||||
R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager));
|
||||
}
|
||||
|
||||
Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KResourceLimit *resource_limit) {
|
||||
Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
||||
/* Validate the region. */
|
||||
MESOSPHERE_ABORT_UNLESS(start <= code_address);
|
||||
MESOSPHERE_ABORT_UNLESS(code_address < code_address + code_size);
|
||||
@@ -186,8 +187,8 @@ namespace ams::kern {
|
||||
m_address_space_start = start;
|
||||
m_address_space_end = end;
|
||||
m_is_kernel = false;
|
||||
m_memory_block_slab_manager = mem_block_slab_manager;
|
||||
m_block_info_manager = block_info_manager;
|
||||
m_memory_block_slab_manager = system_resource->GetMemoryBlockSlabManagerPointer();
|
||||
m_block_info_manager = system_resource->GetBlockInfoManagerPointer();
|
||||
m_resource_limit = resource_limit;
|
||||
|
||||
/* Determine the region we can place our undetermineds in. */
|
||||
@@ -287,6 +288,7 @@ namespace ams::kern {
|
||||
m_max_heap_size = 0;
|
||||
m_mapped_physical_memory_size = 0;
|
||||
m_mapped_unsafe_physical_memory = 0;
|
||||
m_mapped_insecure_memory = 0;
|
||||
m_mapped_ipc_server_memory = 0;
|
||||
|
||||
const bool fill_memory = KTargetSystem::IsDebugMemoryFillEnabled();
|
||||
@@ -340,6 +342,13 @@ namespace ams::kern {
|
||||
Kernel::GetUnsafeMemory().Release(m_mapped_unsafe_physical_memory);
|
||||
}
|
||||
|
||||
/* Release any insecure mapped memory. */
|
||||
if (m_mapped_insecure_memory) {
|
||||
if (auto * const insecure_resource_limit = KSystemControl::GetInsecureMemoryResourceLimit(); insecure_resource_limit != nullptr) {
|
||||
insecure_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, m_mapped_insecure_memory);
|
||||
}
|
||||
}
|
||||
|
||||
/* Release any ipc server memory. */
|
||||
if (m_mapped_ipc_server_memory) {
|
||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, m_mapped_ipc_server_memory);
|
||||
@@ -375,6 +384,7 @@ namespace ams::kern {
|
||||
case KMemoryState_GeneratedCode:
|
||||
case KMemoryState_CodeOut:
|
||||
case KMemoryState_Coverage:
|
||||
case KMemoryState_Insecure:
|
||||
return m_alias_code_region_start;
|
||||
case KMemoryState_Code:
|
||||
case KMemoryState_CodeData:
|
||||
@@ -409,6 +419,7 @@ namespace ams::kern {
|
||||
case KMemoryState_GeneratedCode:
|
||||
case KMemoryState_CodeOut:
|
||||
case KMemoryState_Coverage:
|
||||
case KMemoryState_Insecure:
|
||||
return m_alias_code_region_end - m_alias_code_region_start;
|
||||
case KMemoryState_Code:
|
||||
case KMemoryState_CodeData:
|
||||
@@ -446,6 +457,7 @@ namespace ams::kern {
|
||||
case KMemoryState_GeneratedCode:
|
||||
case KMemoryState_CodeOut:
|
||||
case KMemoryState_Coverage:
|
||||
case KMemoryState_Insecure:
|
||||
return is_in_region && !is_in_heap && !is_in_alias;
|
||||
case KMemoryState_Normal:
|
||||
MESOSPHERE_ASSERT(is_in_heap);
|
||||
@@ -1038,6 +1050,97 @@ namespace ams::kern {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
|
||||
/* Get the insecure memory resource limit and pool. */
|
||||
auto * const insecure_resource_limit = KSystemControl::GetInsecureMemoryResourceLimit();
|
||||
const auto insecure_pool = static_cast<KMemoryManager::Pool>(KSystemControl::GetInsecureMemoryPool());
|
||||
|
||||
/* Reserve the insecure memory. */
|
||||
/* NOTE: ResultOutOfMemory is returned here instead of the usual LimitReached. */
|
||||
KScopedResourceReservation memory_reservation(insecure_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, size);
|
||||
R_UNLESS(memory_reservation.Succeeded(), svc::ResultOutOfMemory());
|
||||
|
||||
/* Allocate pages for the insecure memory. */
|
||||
KPageGroup pg(m_block_info_manager);
|
||||
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), size / PageSize, KMemoryManager::EncodeOption(insecure_pool, KMemoryManager::Direction_FromFront)));
|
||||
|
||||
/* Close the opened pages when we're done with them. */
|
||||
/* If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed automatically. */
|
||||
ON_SCOPE_EXIT { pg.Close(); };
|
||||
|
||||
/* Clear all the newly allocated pages. */
|
||||
for (const auto &it : pg) {
|
||||
std::memset(GetVoidPointer(GetHeapVirtualAddress(it.GetAddress())), m_heap_fill_value, it.GetSize());
|
||||
}
|
||||
|
||||
/* Lock the table. */
|
||||
KScopedLightLock lk(m_general_lock);
|
||||
|
||||
/* Validate that the address's state is valid. */
|
||||
size_t num_allocator_blocks;
|
||||
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||
|
||||
/* Create an update allocator. */
|
||||
Result allocator_result;
|
||||
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks);
|
||||
R_TRY(allocator_result);
|
||||
|
||||
/* We're going to perform an update, so create a helper. */
|
||||
KScopedPageTableUpdater updater(this);
|
||||
|
||||
/* Map the pages. */
|
||||
const size_t num_pages = size / PageSize;
|
||||
const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, DisableMergeAttribute_DisableHead };
|
||||
R_TRY(this->Operate(updater.GetPageList(), address, num_pages, pg, map_properties, OperationType_MapGroup, false));
|
||||
|
||||
/* Apply the memory block update. */
|
||||
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Insecure, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None);
|
||||
|
||||
/* Update our mapped insecure size. */
|
||||
m_mapped_insecure_memory += size;
|
||||
|
||||
/* Commit the memory reservation. */
|
||||
memory_reservation.Commit();
|
||||
|
||||
/* We succeeded. */
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KPageTableBase::UnmapInsecureMemory(KProcessAddress address, size_t size) {
|
||||
/* Lock the table. */
|
||||
KScopedLightLock lk(m_general_lock);
|
||||
|
||||
/* Check the memory state. */
|
||||
size_t num_allocator_blocks;
|
||||
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, KMemoryState_Insecure, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||
|
||||
/* Create an update allocator. */
|
||||
Result allocator_result;
|
||||
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result), m_memory_block_slab_manager, num_allocator_blocks);
|
||||
R_TRY(allocator_result);
|
||||
|
||||
/* We're going to perform an update, so create a helper. */
|
||||
KScopedPageTableUpdater updater(this);
|
||||
|
||||
/* Unmap the memory. */
|
||||
const size_t num_pages = size / PageSize;
|
||||
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
||||
R_TRY(this->Operate(updater.GetPageList(), address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
|
||||
|
||||
/* Apply the memory block update. */
|
||||
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal);
|
||||
|
||||
/* Update our mapped insecure size. */
|
||||
m_mapped_insecure_memory -= size;
|
||||
|
||||
/* Release the insecure memory from the insecure limit. */
|
||||
if (auto * const insecure_resource_limit = KSystemControl::GetInsecureMemoryResourceLimit(); insecure_resource_limit != nullptr) {
|
||||
insecure_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, size);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
KProcessAddress KPageTableBase::FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const {
|
||||
KProcessAddress address = Null<KProcessAddress>;
|
||||
|
||||
@@ -1384,11 +1487,8 @@ namespace ams::kern {
|
||||
TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0 };
|
||||
R_UNLESS(impl.BeginTraversal(std::addressof(cur_entry), std::addressof(context), address), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* The region we're traversing has to be heap. */
|
||||
const KPhysicalAddress phys_address = cur_entry.phys_addr;
|
||||
R_UNLESS(this->IsHeapPhysicalAddress(phys_address), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Traverse until we have enough size or we aren't contiguous any more. */
|
||||
const KPhysicalAddress phys_address = cur_entry.phys_addr;
|
||||
size_t contig_size;
|
||||
for (contig_size = cur_entry.block_size - (GetInteger(phys_address) & (cur_entry.block_size - 1)); contig_size < size; contig_size += cur_entry.block_size) {
|
||||
if (!impl.ContinueTraversal(std::addressof(cur_entry), std::addressof(context))) {
|
||||
@@ -1402,11 +1502,11 @@ namespace ams::kern {
|
||||
/* Take the minimum size for our region. */
|
||||
size = std::min(size, contig_size);
|
||||
|
||||
/* Check that the memory is contiguous. */
|
||||
R_TRY(this->CheckMemoryStateContiguous(address, size,
|
||||
state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted,
|
||||
perm_mask, perm,
|
||||
attr_mask, attr));
|
||||
/* Check that the memory is contiguous (modulo the reference count bit). */
|
||||
const u32 test_state_mask = state_mask | KMemoryState_FlagReferenceCounted;
|
||||
if (R_FAILED(this->CheckMemoryStateContiguous(address, size, test_state_mask, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr))) {
|
||||
R_TRY(this->CheckMemoryStateContiguous(address, size, test_state_mask, state, perm_mask, perm, attr_mask, attr));
|
||||
}
|
||||
|
||||
/* The memory is contiguous, so set the output range. */
|
||||
*out = {
|
||||
@@ -1913,7 +2013,7 @@ namespace ams::kern {
|
||||
R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, phys_addr, true, properties, OperationType_Map, false));
|
||||
|
||||
/* Update the blocks. */
|
||||
m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Io, perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None);
|
||||
m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Io, perm, KMemoryAttribute_Locked, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None);
|
||||
|
||||
/* We successfully mapped the pages. */
|
||||
R_SUCCEED();
|
||||
@@ -1927,7 +2027,7 @@ namespace ams::kern {
|
||||
|
||||
/* Validate the memory state. */
|
||||
size_t num_allocator_blocks;
|
||||
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Io, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Io, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_Locked));
|
||||
|
||||
/* Validate that the region being unmapped corresponds to the physical range described. */
|
||||
{
|
||||
@@ -2687,7 +2787,7 @@ namespace ams::kern {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KPageTableBase::LockForMapDeviceAddressSpace(KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
|
||||
Result KPageTableBase::LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) {
|
||||
/* Lightly validate the range before doing anything else. */
|
||||
const size_t num_pages = size / PageSize;
|
||||
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||
@@ -2696,9 +2796,10 @@ namespace ams::kern {
|
||||
KScopedLightLock lk(m_general_lock);
|
||||
|
||||
/* Check the memory state. */
|
||||
const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap);
|
||||
const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap) | (check_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_None);
|
||||
size_t num_allocator_blocks;
|
||||
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared));
|
||||
KMemoryState old_state;
|
||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), nullptr, nullptr, std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm, perm, KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None, KMemoryAttribute_DeviceShared));
|
||||
|
||||
/* Create an update allocator. */
|
||||
Result allocator_result;
|
||||
@@ -2708,10 +2809,13 @@ namespace ams::kern {
|
||||
/* Update the memory blocks. */
|
||||
m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::ShareToDevice, KMemoryPermission_None);
|
||||
|
||||
/* Set whether the locked memory was io. */
|
||||
*out_is_io = old_state == KMemoryState_Io;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KPageTableBase::LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size) {
|
||||
Result KPageTableBase::LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap) {
|
||||
/* Lightly validate the range before doing anything else. */
|
||||
const size_t num_pages = size / PageSize;
|
||||
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||
@@ -2720,10 +2824,11 @@ namespace ams::kern {
|
||||
KScopedLightLock lk(m_general_lock);
|
||||
|
||||
/* Check the memory state. */
|
||||
const u32 test_state = KMemoryState_FlagCanDeviceMap | (check_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_None);
|
||||
size_t num_allocator_blocks;
|
||||
R_TRY(this->CheckMemoryStateContiguous(std::addressof(num_allocator_blocks),
|
||||
address, size,
|
||||
KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDeviceMap, KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDeviceMap,
|
||||
test_state, test_state,
|
||||
KMemoryPermission_None, KMemoryPermission_None,
|
||||
KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared));
|
||||
|
||||
@@ -2798,7 +2903,7 @@ namespace ams::kern {
|
||||
KScopedLightLock lk(m_general_lock);
|
||||
|
||||
/* Get the range. */
|
||||
const u32 test_state = KMemoryState_FlagReferenceCounted | (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap);
|
||||
const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap);
|
||||
R_TRY(this->GetContiguousMemoryRangeWithState(out,
|
||||
address, size,
|
||||
test_state, test_state,
|
||||
@@ -4136,10 +4241,13 @@ namespace ams::kern {
|
||||
|
||||
/* Allocate pages for the new memory. */
|
||||
KPageGroup pg(m_block_info_manager);
|
||||
R_TRY(Kernel::GetMemoryManager().AllocateAndOpenForProcess(std::addressof(pg), (size - mapped_size) / PageSize, m_allocate_option, GetCurrentProcess().GetId(), m_heap_fill_value));
|
||||
R_TRY(Kernel::GetMemoryManager().AllocateForProcess(std::addressof(pg), (size - mapped_size) / PageSize, m_allocate_option, GetCurrentProcess().GetId(), m_heap_fill_value));
|
||||
|
||||
/* Close our reference when we're done. */
|
||||
ON_SCOPE_EXIT { pg.Close(); };
|
||||
/* If we fail in the next bit (or retry), we need to cleanup the pages. */
|
||||
auto pg_guard = SCOPE_GUARD {
|
||||
pg.OpenFirst();
|
||||
pg.Close();
|
||||
};
|
||||
|
||||
/* Map the memory. */
|
||||
{
|
||||
@@ -4206,7 +4314,13 @@ namespace ams::kern {
|
||||
/* We're going to perform an update, so create a helper. */
|
||||
KScopedPageTableUpdater updater(this);
|
||||
|
||||
/* Prepare to iterate over the memory. */
|
||||
auto pg_it = pg.begin();
|
||||
KPhysicalAddress pg_phys_addr = pg_it->GetAddress();
|
||||
size_t pg_pages = pg_it->GetNumPages();
|
||||
|
||||
/* Reset the current tracking address, and make sure we clean up on failure. */
|
||||
pg_guard.Cancel();
|
||||
cur_address = address;
|
||||
ON_RESULT_FAILURE {
|
||||
if (cur_address > address) {
|
||||
@@ -4243,12 +4357,15 @@ namespace ams::kern {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Iterate over the memory. */
|
||||
auto pg_it = pg.begin();
|
||||
KPhysicalAddress pg_phys_addr = pg_it->GetAddress();
|
||||
size_t pg_pages = pg_it->GetNumPages();
|
||||
/* Release any remaining unmapped memory. */
|
||||
Kernel::GetMemoryManager().OpenFirst(pg_phys_addr, pg_pages);
|
||||
Kernel::GetMemoryManager().Close(pg_phys_addr, pg_pages);
|
||||
for (++pg_it; pg_it != pg.end(); ++pg_it) {
|
||||
Kernel::GetMemoryManager().OpenFirst(pg_it->GetAddress(), pg_it->GetNumPages());
|
||||
Kernel::GetMemoryManager().Close(pg_it->GetAddress(), pg_it->GetNumPages());
|
||||
}
|
||||
};
|
||||
|
||||
auto it = m_memory_block_manager.FindIterator(cur_address);
|
||||
while (true) {
|
||||
@@ -4279,7 +4396,7 @@ namespace ams::kern {
|
||||
|
||||
/* Map whatever we can. */
|
||||
const size_t cur_pages = std::min(pg_pages, map_pages);
|
||||
R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_pages, pg_phys_addr, true, map_properties, OperationType_Map, false));
|
||||
R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_pages, pg_phys_addr, true, map_properties, OperationType_MapFirst, false));
|
||||
|
||||
/* Advance. */
|
||||
cur_address += cur_pages * PageSize;
|
||||
@@ -4328,6 +4445,9 @@ namespace ams::kern {
|
||||
const KProcessAddress last_address = address + size - 1;
|
||||
|
||||
/* Define iteration variables. */
|
||||
KProcessAddress map_start_address = Null<KProcessAddress>;
|
||||
KProcessAddress map_last_address = Null<KProcessAddress>;
|
||||
|
||||
KProcessAddress cur_address;
|
||||
size_t mapped_size;
|
||||
size_t num_allocator_blocks = 0;
|
||||
@@ -4354,27 +4474,26 @@ namespace ams::kern {
|
||||
if (is_normal) {
|
||||
R_UNLESS(info.GetAttribute() == KMemoryAttribute_None, svc::ResultInvalidCurrentMemory());
|
||||
|
||||
if (map_start_address == Null<KProcessAddress>) {
|
||||
map_start_address = cur_address;
|
||||
}
|
||||
map_last_address = (last_address >= info.GetLastAddress()) ? info.GetLastAddress() : last_address;
|
||||
|
||||
if (info.GetAddress() < GetInteger(address)) {
|
||||
++num_allocator_blocks;
|
||||
}
|
||||
if (last_address < info.GetLastAddress()) {
|
||||
++num_allocator_blocks;
|
||||
}
|
||||
|
||||
mapped_size += (map_last_address + 1 - cur_address);
|
||||
}
|
||||
|
||||
/* Check if we're done. */
|
||||
if (last_address <= info.GetLastAddress()) {
|
||||
if (is_normal) {
|
||||
mapped_size += (last_address + 1 - cur_address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Track the memory if it's mapped. */
|
||||
if (is_normal) {
|
||||
mapped_size += KProcessAddress(info.GetEndAddress()) - cur_address;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_address = info.GetEndAddress();
|
||||
++it;
|
||||
@@ -4384,54 +4503,6 @@ namespace ams::kern {
|
||||
R_SUCCEED_IF(mapped_size == 0);
|
||||
}
|
||||
|
||||
/* Make a page group for the unmap region. */
|
||||
KPageGroup pg(m_block_info_manager);
|
||||
{
|
||||
auto &impl = this->GetImpl();
|
||||
|
||||
/* Begin traversal. */
|
||||
TraversalContext context;
|
||||
TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0 };
|
||||
bool cur_valid = false;
|
||||
TraversalEntry next_entry;
|
||||
bool next_valid;
|
||||
size_t tot_size = 0;
|
||||
|
||||
cur_address = address;
|
||||
next_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), cur_address);
|
||||
next_entry.block_size = (next_entry.block_size - (GetInteger(next_entry.phys_addr) & (next_entry.block_size - 1)));
|
||||
|
||||
/* Iterate, building the group. */
|
||||
while (true) {
|
||||
if ((!next_valid && !cur_valid) || (next_valid && cur_valid && next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size)) {
|
||||
cur_entry.block_size += next_entry.block_size;
|
||||
} else {
|
||||
if (cur_valid) {
|
||||
MESOSPHERE_ABORT_UNLESS(IsHeapPhysicalAddress(cur_entry.phys_addr));
|
||||
R_TRY(pg.AddBlock(cur_entry.phys_addr, cur_entry.block_size / PageSize));
|
||||
}
|
||||
|
||||
/* Update tracking variables. */
|
||||
tot_size += cur_entry.block_size;
|
||||
cur_entry = next_entry;
|
||||
cur_valid = next_valid;
|
||||
}
|
||||
|
||||
if (cur_entry.block_size + tot_size >= size) {
|
||||
break;
|
||||
}
|
||||
|
||||
next_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context));
|
||||
}
|
||||
|
||||
/* Add the last block. */
|
||||
if (cur_valid) {
|
||||
MESOSPHERE_ABORT_UNLESS(IsHeapPhysicalAddress(cur_entry.phys_addr));
|
||||
R_TRY(pg.AddBlock(cur_entry.phys_addr, (size - tot_size) / PageSize));
|
||||
}
|
||||
}
|
||||
MESOSPHERE_ASSERT(pg.GetNumPages() == mapped_size / PageSize);
|
||||
|
||||
/* Create an update allocator. */
|
||||
MESOSPHERE_ASSERT(num_allocator_blocks <= KMemoryBlockManagerUpdateAllocator::MaxBlocks);
|
||||
Result allocator_result;
|
||||
@@ -4441,69 +4512,12 @@ namespace ams::kern {
|
||||
/* We're going to perform an update, so create a helper. */
|
||||
KScopedPageTableUpdater updater(this);
|
||||
|
||||
/* Open a reference to the pages, we're unmapping, and close the reference when we're done. */
|
||||
pg.Open();
|
||||
ON_SCOPE_EXIT { pg.Close(); };
|
||||
/* Separate the mapping. */
|
||||
const KPageProperties sep_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
||||
R_TRY(this->Operate(updater.GetPageList(), map_start_address, (map_last_address + 1 - map_start_address) / PageSize, Null<KPhysicalAddress>, false, sep_properties, OperationType_Separate, false));
|
||||
|
||||
/* Reset the current tracking address, and make sure we clean up on failure. */
|
||||
cur_address = address;
|
||||
ON_RESULT_FAILURE {
|
||||
if (cur_address > address) {
|
||||
const KProcessAddress last_map_address = cur_address - 1;
|
||||
cur_address = address;
|
||||
|
||||
/* Iterate over the memory we unmapped. */
|
||||
auto it = m_memory_block_manager.FindIterator(cur_address);
|
||||
auto pg_it = pg.begin();
|
||||
KPhysicalAddress pg_phys_addr = pg_it->GetAddress();
|
||||
size_t pg_pages = pg_it->GetNumPages();
|
||||
|
||||
while (true) {
|
||||
/* Get the memory info for the pages we unmapped, convert to property. */
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
const KPageProperties prev_properties = { info.GetPermission(), false, false, DisableMergeAttribute_None };
|
||||
|
||||
/* If the memory is normal, we unmapped it and need to re-map it. */
|
||||
if (info.GetState() == KMemoryState_Normal) {
|
||||
/* Determine the range to map. */
|
||||
size_t map_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_map_address + 1 - cur_address) / PageSize;
|
||||
|
||||
/* While we have pages to map, map them. */
|
||||
while (map_pages > 0) {
|
||||
/* Check if we're at the end of the physical block. */
|
||||
if (pg_pages == 0) {
|
||||
/* Ensure there are more pages to map. */
|
||||
MESOSPHERE_ABORT_UNLESS(pg_it != pg.end());
|
||||
|
||||
/* Advance our physical block. */
|
||||
++pg_it;
|
||||
pg_phys_addr = pg_it->GetAddress();
|
||||
pg_pages = pg_it->GetNumPages();
|
||||
}
|
||||
|
||||
/* Map whatever we can. */
|
||||
const size_t cur_pages = std::min(pg_pages, map_pages);
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_pages, pg_phys_addr, true, prev_properties, OperationType_Map, true));
|
||||
|
||||
/* Advance. */
|
||||
cur_address += cur_pages * PageSize;
|
||||
map_pages -= cur_pages;
|
||||
|
||||
pg_phys_addr += cur_pages * PageSize;
|
||||
pg_pages -= cur_pages;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we're done. */
|
||||
if (last_map_address <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
++it;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Iterate over the memory, unmapping as we go. */
|
||||
auto it = m_memory_block_manager.FindIterator(cur_address);
|
||||
@@ -4521,7 +4535,7 @@ namespace ams::kern {
|
||||
const size_t cur_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_address + 1 - cur_address) / PageSize;
|
||||
|
||||
/* Unmap. */
|
||||
R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
|
||||
}
|
||||
|
||||
/* Check if we're done. */
|
||||
|
||||
@@ -117,34 +117,19 @@ namespace ams::kern {
|
||||
this->DeleteThreadLocalRegion(m_plr_address);
|
||||
|
||||
/* Get the used memory size. */
|
||||
const size_t used_memory_size = this->GetUsedUserPhysicalMemorySize();
|
||||
const size_t used_memory_size = this->GetUsedNonSystemUserPhysicalMemorySize();
|
||||
|
||||
/* Finalize the page table. */
|
||||
m_page_table.Finalize();
|
||||
|
||||
/* Free the system resource. */
|
||||
if (m_system_resource_address != Null<KVirtualAddress>) {
|
||||
/* Check that we have no outstanding allocations. */
|
||||
MESOSPHERE_ABORT_UNLESS(m_memory_block_slab_manager.GetUsed() == 0);
|
||||
MESOSPHERE_ABORT_UNLESS(m_block_info_manager.GetUsed() == 0);
|
||||
MESOSPHERE_ABORT_UNLESS(m_page_table_manager.GetUsed() == 0);
|
||||
/* Finish using our system resource. */
|
||||
{
|
||||
if (m_system_resource->IsSecureResource()) {
|
||||
/* Finalize optimized memory. If memory wasn't optimized, this is a no-op. */
|
||||
Kernel::GetMemoryManager().FinalizeOptimizedMemory(this->GetId(), m_memory_pool);
|
||||
}
|
||||
|
||||
/* Free the memory. */
|
||||
KSystemControl::FreeSecureMemory(m_system_resource_address, m_system_resource_num_pages * PageSize, m_memory_pool);
|
||||
|
||||
/* Clear our tracking variables. */
|
||||
m_system_resource_address = Null<KVirtualAddress>;
|
||||
m_system_resource_num_pages = 0;
|
||||
|
||||
/* Finalize optimized memory. If memory wasn't optimized, this is a no-op. */
|
||||
Kernel::GetMemoryManager().FinalizeOptimizedMemory(this->GetId(), m_memory_pool);
|
||||
}
|
||||
|
||||
/* Release memory to the resource limit. */
|
||||
if (m_resource_limit != nullptr) {
|
||||
MESOSPHERE_ABORT_UNLESS(used_memory_size >= m_memory_release_hint);
|
||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, used_memory_size, used_memory_size - m_memory_release_hint);
|
||||
m_resource_limit->Close();
|
||||
m_system_resource->Close();
|
||||
}
|
||||
|
||||
/* Free all shared memory infos. */
|
||||
@@ -179,6 +164,13 @@ namespace ams::kern {
|
||||
MESOSPHERE_ABORT_UNLESS(m_partially_used_tlp_tree.empty());
|
||||
MESOSPHERE_ABORT_UNLESS(m_fully_used_tlp_tree.empty());
|
||||
|
||||
/* Release memory to the resource limit. */
|
||||
if (m_resource_limit != nullptr) {
|
||||
MESOSPHERE_ABORT_UNLESS(used_memory_size >= m_memory_release_hint);
|
||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, used_memory_size, used_memory_size - m_memory_release_hint);
|
||||
m_resource_limit->Close();
|
||||
}
|
||||
|
||||
/* Log that we finalized for debug. */
|
||||
MESOSPHERE_LOG("KProcess::Finalize() pid=%ld name=%-12s\n", m_process_id, m_name);
|
||||
|
||||
@@ -267,13 +259,18 @@ namespace ams::kern {
|
||||
MESOSPHERE_ASSERT(res_limit != nullptr);
|
||||
MESOSPHERE_ABORT_UNLESS((params.code_num_pages * PageSize) / PageSize == static_cast<size_t>(params.code_num_pages));
|
||||
|
||||
/* Determine is application. */
|
||||
const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication) != 0;
|
||||
|
||||
/* Set members. */
|
||||
m_memory_pool = pool;
|
||||
m_resource_limit = res_limit;
|
||||
m_system_resource_address = Null<KVirtualAddress>;
|
||||
m_system_resource_num_pages = 0;
|
||||
m_system_resource = std::addressof(is_app ? Kernel::GetApplicationSystemResource() : Kernel::GetSystemSystemResource());
|
||||
m_is_immortal = immortal;
|
||||
|
||||
/* Open reference to our system resource. */
|
||||
m_system_resource->Open();
|
||||
|
||||
/* Setup page table. */
|
||||
/* NOTE: Nintendo passes process ID despite not having set it yet. */
|
||||
/* This goes completely unused, but even so... */
|
||||
@@ -281,11 +278,7 @@ namespace ams::kern {
|
||||
const auto as_type = static_cast<ams::svc::CreateProcessFlag>(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask);
|
||||
const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
||||
const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
||||
const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication) != 0;
|
||||
auto *mem_block_manager = std::addressof(is_app ? Kernel::GetApplicationMemoryBlockManager() : Kernel::GetSystemMemoryBlockManager());
|
||||
auto *block_info_manager = std::addressof(is_app ? Kernel::GetApplicationBlockInfoManager() : Kernel::GetSystemBlockInfoManager());
|
||||
auto *pt_manager = std::addressof(is_app ? Kernel::GetApplicationPageTableManager() : Kernel::GetSystemPageTableManager());
|
||||
R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, params.code_num_pages * PageSize, mem_block_manager, block_info_manager, pt_manager, res_limit));
|
||||
R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, params.code_num_pages * PageSize, m_system_resource, res_limit));
|
||||
}
|
||||
ON_RESULT_FAILURE { m_page_table.Finalize(); };
|
||||
|
||||
@@ -328,64 +321,35 @@ namespace ams::kern {
|
||||
const size_t code_size = code_num_pages * PageSize;
|
||||
const size_t system_resource_size = system_resource_num_pages * PageSize;
|
||||
|
||||
/* Reserve memory for the system resource. */
|
||||
KScopedResourceReservation memory_reservation(this, ams::svc::LimitableResource_PhysicalMemoryMax, code_size + KSystemControl::CalculateRequiredSecureMemorySize(system_resource_size, pool));
|
||||
/* Reserve memory for our code resource. */
|
||||
KScopedResourceReservation memory_reservation(this, ams::svc::LimitableResource_PhysicalMemoryMax, code_size);
|
||||
R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached());
|
||||
|
||||
/* Setup page table resource objects. */
|
||||
KMemoryBlockSlabManager *mem_block_manager;
|
||||
KBlockInfoManager *block_info_manager;
|
||||
KPageTableManager *pt_manager;
|
||||
|
||||
m_system_resource_address = Null<KVirtualAddress>;
|
||||
m_system_resource_num_pages = 0;
|
||||
|
||||
/* Setup our system resource. */
|
||||
if (system_resource_num_pages != 0) {
|
||||
/* Allocate secure memory. */
|
||||
R_TRY(KSystemControl::AllocateSecureMemory(std::addressof(m_system_resource_address), system_resource_size, pool));
|
||||
/* Create a secure system resource. */
|
||||
KSecureSystemResource *secure_resource = KSecureSystemResource::Create();
|
||||
R_UNLESS(secure_resource != nullptr, svc::ResultOutOfResource());
|
||||
|
||||
/* Set the number of system resource pages. */
|
||||
MESOSPHERE_ASSERT(m_system_resource_address != Null<KVirtualAddress>);
|
||||
m_system_resource_num_pages = system_resource_num_pages;
|
||||
ON_RESULT_FAILURE { secure_resource->Close(); };
|
||||
|
||||
/* Initialize slab heaps. */
|
||||
const size_t rc_size = util::AlignUp(KPageTableSlabHeap::CalculateReferenceCountSize(system_resource_size), PageSize);
|
||||
m_dynamic_page_manager.Initialize(m_system_resource_address + rc_size, system_resource_size - rc_size);
|
||||
m_page_table_heap.Initialize(std::addressof(m_dynamic_page_manager), 0, GetPointer<KPageTableManager::RefCount>(m_system_resource_address));
|
||||
m_memory_block_heap.Initialize(std::addressof(m_dynamic_page_manager), 0);
|
||||
m_block_info_heap.Initialize(std::addressof(m_dynamic_page_manager), 0);
|
||||
/* Initialize the secure resource. */
|
||||
R_TRY(secure_resource->Initialize(system_resource_size, m_resource_limit, m_memory_pool));
|
||||
|
||||
/* Initialize managers. */
|
||||
m_page_table_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_page_table_heap));
|
||||
m_memory_block_slab_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_memory_block_heap));
|
||||
m_block_info_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_block_info_heap));
|
||||
/* Set our system resource. */
|
||||
m_system_resource = secure_resource;
|
||||
|
||||
mem_block_manager = std::addressof(m_memory_block_slab_manager);
|
||||
block_info_manager = std::addressof(m_block_info_manager);
|
||||
pt_manager = std::addressof(m_page_table_manager);
|
||||
} else {
|
||||
const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication);
|
||||
mem_block_manager = std::addressof(is_app ? Kernel::GetApplicationMemoryBlockManager() : Kernel::GetSystemMemoryBlockManager());
|
||||
block_info_manager = std::addressof(is_app ? Kernel::GetApplicationBlockInfoManager() : Kernel::GetSystemBlockInfoManager());
|
||||
pt_manager = std::addressof(is_app ? Kernel::GetApplicationPageTableManager() : Kernel::GetSystemPageTableManager());
|
||||
/* Use the system-wide system resource. */
|
||||
const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication);
|
||||
m_system_resource = std::addressof(is_app ? Kernel::GetApplicationSystemResource() : Kernel::GetSystemSystemResource());
|
||||
|
||||
/* Open reference to the system resource. */
|
||||
m_system_resource->Open();
|
||||
}
|
||||
|
||||
/* Ensure we don't leak any secure memory we allocated. */
|
||||
ON_RESULT_FAILURE {
|
||||
if (m_system_resource_address != Null<KVirtualAddress>) {
|
||||
/* Check that we have no outstanding allocations. */
|
||||
MESOSPHERE_ABORT_UNLESS(m_memory_block_slab_manager.GetUsed() == 0);
|
||||
MESOSPHERE_ABORT_UNLESS(m_block_info_manager.GetUsed() == 0);
|
||||
MESOSPHERE_ABORT_UNLESS(m_page_table_manager.GetUsed() == 0);
|
||||
|
||||
/* Free the memory. */
|
||||
KSystemControl::FreeSecureMemory(m_system_resource_address, system_resource_size, pool);
|
||||
|
||||
/* Clear our tracking variables. */
|
||||
m_system_resource_address = Null<KVirtualAddress>;
|
||||
m_system_resource_num_pages = 0;
|
||||
}
|
||||
};
|
||||
/* Ensure we clean up our secure resource, if we fail. */
|
||||
ON_RESULT_FAILURE { m_system_resource->Close(); };
|
||||
|
||||
/* Setup page table. */
|
||||
/* NOTE: Nintendo passes process ID despite not having set it yet. */
|
||||
@@ -394,7 +358,7 @@ namespace ams::kern {
|
||||
const auto as_type = static_cast<ams::svc::CreateProcessFlag>(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask);
|
||||
const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
||||
const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
||||
R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, code_size, mem_block_manager, block_info_manager, pt_manager, res_limit));
|
||||
R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, code_size, m_system_resource, res_limit));
|
||||
}
|
||||
ON_RESULT_FAILURE_2 { m_page_table.Finalize(); };
|
||||
|
||||
@@ -413,7 +377,7 @@ namespace ams::kern {
|
||||
MESOSPHERE_ABORT_UNLESS(m_process_id <= ProcessIdMax);
|
||||
|
||||
/* If we should optimize memory allocations, do so. */
|
||||
if (m_system_resource_address != Null<KVirtualAddress> && (params.flags & ams::svc::CreateProcessFlag_OptimizeMemoryAllocation) != 0) {
|
||||
if (m_system_resource->IsSecureResource() && (params.flags & ams::svc::CreateProcessFlag_OptimizeMemoryAllocation) != 0) {
|
||||
R_TRY(Kernel::GetMemoryManager().InitializeOptimizedMemory(m_process_id, pool));
|
||||
}
|
||||
|
||||
@@ -461,7 +425,7 @@ namespace ams::kern {
|
||||
if (!m_is_immortal) {
|
||||
/* Release resource limit hint. */
|
||||
if (m_resource_limit != nullptr) {
|
||||
m_memory_release_hint = this->GetUsedUserPhysicalMemorySize();
|
||||
m_memory_release_hint = this->GetUsedNonSystemUserPhysicalMemorySize();
|
||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, 0, m_memory_release_hint);
|
||||
}
|
||||
|
||||
@@ -880,7 +844,7 @@ namespace ams::kern {
|
||||
size_t KProcess::GetUsedUserPhysicalMemorySize() const {
|
||||
const size_t norm_size = m_page_table.GetNormalMemorySize();
|
||||
const size_t other_size = m_code_size + m_main_thread_stack_size;
|
||||
const size_t sec_size = KSystemControl::CalculateRequiredSecureMemorySize(m_system_resource_num_pages * PageSize, m_memory_pool);
|
||||
const size_t sec_size = m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->CalculateRequiredSecureMemorySize() : 0;
|
||||
|
||||
return norm_size + other_size + sec_size;
|
||||
}
|
||||
@@ -909,7 +873,7 @@ namespace ams::kern {
|
||||
/* Get the amount of free and used size. */
|
||||
const size_t free_size = m_resource_limit->GetFreeValue(ams::svc::LimitableResource_PhysicalMemoryMax);
|
||||
const size_t used_size = this->GetUsedUserPhysicalMemorySize();
|
||||
const size_t sec_size = KSystemControl::CalculateRequiredSecureMemorySize(m_system_resource_num_pages * PageSize, m_memory_pool);
|
||||
const size_t sec_size = m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->CalculateRequiredSecureMemorySize() : 0;
|
||||
const size_t max_size = m_max_process_memory;
|
||||
|
||||
if (used_size + free_size > max_size) {
|
||||
|
||||
@@ -88,6 +88,10 @@ namespace ams::kern {
|
||||
return m_recv_list_count > ipc::MessageBuffer::MessageHeader::ReceiveListCountType_CountOffset;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE bool IsToMessageBuffer() const {
|
||||
return m_recv_list_count == ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer;
|
||||
}
|
||||
|
||||
void GetBuffer(uintptr_t &out, size_t size, int &key) const {
|
||||
switch (m_recv_list_count) {
|
||||
case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_None:
|
||||
@@ -264,12 +268,12 @@ namespace ams::kern {
|
||||
static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite),
|
||||
KMemoryAttribute_Uncached | KMemoryAttribute_Locked, KMemoryAttribute_Locked,
|
||||
src_pointer,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
KMemoryState_FlagLinearMapped, KMemoryState_FlagLinearMapped,
|
||||
KMemoryPermission_UserRead,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||
} else {
|
||||
R_TRY(src_page_table.CopyMemoryFromLinearToUser(recv_pointer, recv_size, src_pointer,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
KMemoryState_FlagLinearMapped, KMemoryState_FlagLinearMapped,
|
||||
KMemoryPermission_UserRead,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||
}
|
||||
@@ -642,12 +646,15 @@ namespace ams::kern {
|
||||
const size_t max_fast_size = std::min<size_t>(offset_words + raw_size, PageSize);
|
||||
const size_t fast_size = max_fast_size - offset_words;
|
||||
|
||||
/* Determine source state; if user buffer, we require heap, and otherwise only linear mapped (to enable tls use). */
|
||||
const auto src_state = src_user ? KMemoryState_FlagReferenceCounted : KMemoryState_FlagLinearMapped;
|
||||
|
||||
/* Determine the source permission. User buffer should be unmapped + read, TLS should be user readable. */
|
||||
const KMemoryPermission src_perm = static_cast<KMemoryPermission>(src_user ? KMemoryPermission_NotMapped | KMemoryPermission_KernelRead : KMemoryPermission_UserRead);
|
||||
|
||||
/* Perform the fast part of the copy. */
|
||||
R_TRY(src_page_table.CopyMemoryFromLinearToKernel(reinterpret_cast<uintptr_t>(dst_msg_ptr) + offset_words, fast_size, src_message_buffer + offset_words,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
src_state, src_state,
|
||||
src_perm,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||
|
||||
@@ -658,7 +665,7 @@ namespace ams::kern {
|
||||
static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite),
|
||||
KMemoryAttribute_Uncached | KMemoryAttribute_Locked, KMemoryAttribute_Locked,
|
||||
src_message_buffer + max_fast_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
src_state, src_state,
|
||||
src_perm,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||
}
|
||||
@@ -744,9 +751,11 @@ namespace ams::kern {
|
||||
R_UNLESS(recv_pointer != 0, svc::ResultOutOfResource());
|
||||
|
||||
/* Perform the pointer data copy. */
|
||||
const KMemoryPermission dst_perm = static_cast<KMemoryPermission>(dst_user ? KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite : KMemoryPermission_UserReadWrite);
|
||||
const bool dst_heap = dst_user && dst_recv_list.IsToMessageBuffer();
|
||||
const auto dst_state = dst_heap ? KMemoryState_FlagReferenceCounted : KMemoryState_FlagLinearMapped;
|
||||
const KMemoryPermission dst_perm = static_cast<KMemoryPermission>(dst_heap ? KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite : KMemoryPermission_UserReadWrite);
|
||||
R_TRY(dst_page_table.CopyMemoryFromUserToLinear(recv_pointer, recv_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
dst_state, dst_state,
|
||||
dst_perm,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None,
|
||||
src_pointer));
|
||||
@@ -898,12 +907,15 @@ namespace ams::kern {
|
||||
const size_t max_fast_size = std::min<size_t>(offset_words + raw_size, PageSize);
|
||||
const size_t fast_size = max_fast_size - offset_words;
|
||||
|
||||
/* Determine dst state; if user buffer, we require heap, and otherwise only linear mapped (to enable tls use). */
|
||||
const auto dst_state = dst_user ? KMemoryState_FlagReferenceCounted : KMemoryState_FlagLinearMapped;
|
||||
|
||||
/* Determine the dst permission. User buffer should be unmapped + read, TLS should be user readable. */
|
||||
const KMemoryPermission dst_perm = static_cast<KMemoryPermission>(dst_user ? KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite : KMemoryPermission_UserReadWrite);
|
||||
|
||||
/* Perform the fast part of the copy. */
|
||||
R_TRY(dst_page_table.CopyMemoryFromKernelToLinear(dst_message_buffer + offset_words, fast_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
dst_state, dst_state,
|
||||
dst_perm,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None,
|
||||
reinterpret_cast<uintptr_t>(src_msg_ptr) + offset_words));
|
||||
@@ -911,7 +923,7 @@ namespace ams::kern {
|
||||
/* If the fast part of the copy didn't get everything, perform the slow part of the copy. */
|
||||
if (fast_size < raw_size) {
|
||||
R_TRY(dst_page_table.CopyMemoryFromHeapToHeap(dst_page_table, dst_message_buffer + max_fast_size, raw_size - fast_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
dst_state, dst_state,
|
||||
dst_perm,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None,
|
||||
src_message_buffer + max_fast_size,
|
||||
|
||||
@@ -19,22 +19,20 @@ namespace ams::kern {
|
||||
|
||||
Result KSessionRequest::SessionMappings::PushMap(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state, size_t index) {
|
||||
/* At most 15 buffers of each type (4-bit descriptor counts). */
|
||||
MESOSPHERE_ASSERT(index < ((1ul << 4) - 1) * 3);
|
||||
MESOSPHERE_ASSERT(index < NumMappings);
|
||||
|
||||
/* Get the mapping. */
|
||||
Mapping *mapping;
|
||||
if (index < NumStaticMappings) {
|
||||
mapping = std::addressof(m_static_mappings[index]);
|
||||
} else {
|
||||
/* Allocate a page for the extra mappings. */
|
||||
if (m_mappings == nullptr) {
|
||||
KPageBuffer *page_buffer = KPageBuffer::Allocate();
|
||||
R_UNLESS(page_buffer != nullptr, svc::ResultOutOfMemory());
|
||||
|
||||
m_mappings = reinterpret_cast<Mapping *>(page_buffer);
|
||||
/* Allocate dynamic mappings as necessary. */
|
||||
if (m_dynamic_mappings == nullptr) {
|
||||
m_dynamic_mappings = DynamicMappings::Allocate();
|
||||
R_UNLESS(m_dynamic_mappings != nullptr, svc::ResultOutOfMemory());
|
||||
}
|
||||
|
||||
mapping = std::addressof(m_mappings[index - NumStaticMappings]);
|
||||
mapping = std::addressof(m_dynamic_mappings->Get(index - NumStaticMappings));
|
||||
}
|
||||
|
||||
/* Set the mapping. */
|
||||
@@ -59,9 +57,9 @@ namespace ams::kern {
|
||||
}
|
||||
|
||||
void KSessionRequest::SessionMappings::Finalize() {
|
||||
if (m_mappings) {
|
||||
KPageBuffer::Free(reinterpret_cast<KPageBuffer *>(m_mappings));
|
||||
m_mappings = nullptr;
|
||||
if (m_dynamic_mappings) {
|
||||
DynamicMappings::Free(m_dynamic_mappings);
|
||||
m_dynamic_mappings = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -292,4 +292,13 @@ namespace ams::kern {
|
||||
Kernel::GetMemoryManager().Close(KPageTable::GetHeapPhysicalAddress(address), size / PageSize);
|
||||
}
|
||||
|
||||
/* Insecure Memory. */
|
||||
KResourceLimit *KSystemControlBase::GetInsecureMemoryResourceLimit() {
|
||||
return std::addressof(Kernel::GetSystemResourceLimit());
|
||||
}
|
||||
|
||||
u32 KSystemControlBase::GetInsecureMemoryPool() {
|
||||
return KMemoryManager::Pool_SystemNonSecure;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
90
libraries/libmesosphere/source/kern_k_system_resource.cpp
Normal file
90
libraries/libmesosphere/source/kern_k_system_resource.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 <mesosphere.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
Result KSecureSystemResource::Initialize(size_t size, KResourceLimit *resource_limit, KMemoryManager::Pool pool) {
|
||||
/* Set members. */
|
||||
m_resource_limit = resource_limit;
|
||||
m_resource_size = size;
|
||||
m_resource_pool = pool;
|
||||
|
||||
/* Determine required size for our secure resource. */
|
||||
const size_t secure_size = this->CalculateRequiredSecureMemorySize();
|
||||
|
||||
/* Reserve memory for our secure resource. */
|
||||
KScopedResourceReservation memory_reservation(m_resource_limit, ams::svc::LimitableResource_PhysicalMemoryMax, secure_size);
|
||||
R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached());
|
||||
|
||||
/* Allocate secure memory. */
|
||||
R_TRY(KSystemControl::AllocateSecureMemory(std::addressof(m_resource_address), m_resource_size, m_resource_pool));
|
||||
MESOSPHERE_ASSERT(m_resource_address != Null<KVirtualAddress>);
|
||||
|
||||
/* Ensure we clean up the secure memory, if we fail past this point. */
|
||||
ON_RESULT_FAILURE { KSystemControl::FreeSecureMemory(m_resource_address, m_resource_size, m_resource_pool); };
|
||||
|
||||
/* Check that our allocation is bigger than the reference counts needed for it. */
|
||||
const size_t rc_size = util::AlignUp(KPageTableSlabHeap::CalculateReferenceCountSize(m_resource_size), PageSize);
|
||||
R_UNLESS(m_resource_size > rc_size, svc::ResultOutOfMemory());
|
||||
|
||||
/* Initialize slab heaps. */
|
||||
m_dynamic_page_manager.Initialize(m_resource_address + rc_size, m_resource_size - rc_size, PageSize);
|
||||
m_page_table_heap.Initialize(std::addressof(m_dynamic_page_manager), 0, GetPointer<KPageTableManager::RefCount>(m_resource_address));
|
||||
m_memory_block_heap.Initialize(std::addressof(m_dynamic_page_manager), 0);
|
||||
m_block_info_heap.Initialize(std::addressof(m_dynamic_page_manager), 0);
|
||||
|
||||
/* Initialize managers. */
|
||||
m_page_table_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_page_table_heap));
|
||||
m_memory_block_slab_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_memory_block_heap));
|
||||
m_block_info_manager.Initialize(std::addressof(m_dynamic_page_manager), std::addressof(m_block_info_heap));
|
||||
|
||||
/* Set our managers. */
|
||||
this->SetManagers(m_memory_block_slab_manager, m_block_info_manager, m_page_table_manager);
|
||||
|
||||
/* Commit the memory reservation. */
|
||||
memory_reservation.Commit();
|
||||
|
||||
/* Open reference to our resource limit. */
|
||||
m_resource_limit->Open();
|
||||
|
||||
/* Set ourselves as initialized. */
|
||||
m_is_initialized = true;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void KSecureSystemResource::Finalize() {
|
||||
/* Check that we have no outstanding allocations. */
|
||||
MESOSPHERE_ABORT_UNLESS(m_memory_block_slab_manager.GetUsed() == 0);
|
||||
MESOSPHERE_ABORT_UNLESS(m_block_info_manager.GetUsed() == 0);
|
||||
MESOSPHERE_ABORT_UNLESS(m_page_table_manager.GetUsed() == 0);
|
||||
|
||||
/* Free our secure memory. */
|
||||
KSystemControl::FreeSecureMemory(m_resource_address, m_resource_size, m_resource_pool);
|
||||
|
||||
/* Release the memory reservation. */
|
||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, this->CalculateRequiredSecureMemorySize());
|
||||
|
||||
/* Close reference to our resource limit. */
|
||||
m_resource_limit->Close();
|
||||
}
|
||||
|
||||
size_t KSecureSystemResource::CalculateRequiredSecureMemorySize(size_t size, KMemoryManager::Pool pool) {
|
||||
return KSystemControl::CalculateRequiredSecureMemorySize(size, pool);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,7 +46,7 @@ namespace ams::kern {
|
||||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().UnmapPages(stack_bottom, 1, KMemoryState_Kernel));
|
||||
|
||||
/* Free the stack page. */
|
||||
KPageBuffer::Free(KPageBuffer::FromPhysicalAddress(stack_paddr));
|
||||
KPageBuffer::FreeChecked<PageSize>(KPageBuffer::FromPhysicalAddress(stack_paddr));
|
||||
}
|
||||
|
||||
class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { /* ... */ };
|
||||
@@ -334,7 +334,7 @@ namespace ams::kern {
|
||||
MESOSPHERE_ABORT_UNLESS(stack_region.GetEndAddress() != 0);
|
||||
|
||||
/* Allocate a page to use as the thread. */
|
||||
KPageBuffer *page = KPageBuffer::Allocate();
|
||||
KPageBuffer *page = KPageBuffer::AllocateChecked<PageSize>();
|
||||
R_UNLESS(page != nullptr, svc::ResultOutOfResource());
|
||||
|
||||
/* Map the stack page. */
|
||||
@@ -509,7 +509,8 @@ namespace ams::kern {
|
||||
|
||||
void KThread::OnLeaveUsermodeException() {
|
||||
this->ClearUsermodeExceptionSvcPermissions();
|
||||
this->ClearInUsermodeExceptionHandler();
|
||||
|
||||
/* NOTE: InUsermodeExceptionHandler will be cleared by RestoreContext. */
|
||||
}
|
||||
|
||||
void KThread::Pin() {
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace ams::kern {
|
||||
m_owner = process;
|
||||
|
||||
/* Allocate a new page. */
|
||||
KPageBuffer *page_buf = KPageBuffer::Allocate();
|
||||
KPageBuffer *page_buf = KPageBuffer::AllocateChecked<PageSize>();
|
||||
R_UNLESS(page_buf != nullptr, svc::ResultOutOfMemory());
|
||||
ON_RESULT_FAILURE { KPageBuffer::Free(page_buf); };
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace ams::kern {
|
||||
R_TRY(m_owner->GetPageTable().UnmapPages(this->GetAddress(), 1, KMemoryState_ThreadLocal));
|
||||
|
||||
/* Free the page. */
|
||||
KPageBuffer::Free(KPageBuffer::FromPhysicalAddress(phys_addr));
|
||||
KPageBuffer::FreeChecked<PageSize>(KPageBuffer::FromPhysicalAddress(phys_addr));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,10 @@ namespace ams::kern {
|
||||
size -= rc_size;
|
||||
|
||||
/* Initialize the resource managers' shared page manager. */
|
||||
g_resource_manager_page_manager.Initialize(address, size);
|
||||
g_resource_manager_page_manager.Initialize(address, size, std::max<size_t>(PageSize, KPageBufferSlabHeap::BufferSize));
|
||||
|
||||
/* Initialize the KPageBuffer slab heap. */
|
||||
KPageBuffer::InitializeSlabHeap(g_resource_manager_page_manager);
|
||||
|
||||
/* Initialize the fixed-size slabheaps. */
|
||||
s_app_memory_block_heap.Initialize(std::addressof(g_resource_manager_page_manager), ApplicationMemoryBlockSlabHeapSize);
|
||||
@@ -100,6 +103,14 @@ namespace ams::kern {
|
||||
|
||||
/* Check that we have the correct number of dynamic pages available. */
|
||||
MESOSPHERE_ABORT_UNLESS(g_resource_manager_page_manager.GetCount() - g_resource_manager_page_manager.GetUsed() == ReservedDynamicPageCount);
|
||||
|
||||
/* Create the system page table managers. */
|
||||
KAutoObject::Create<KSystemResource>(std::addressof(s_app_system_resource));
|
||||
KAutoObject::Create<KSystemResource>(std::addressof(s_sys_system_resource));
|
||||
|
||||
/* Set the managers for the system resources. */
|
||||
s_app_system_resource.SetManagers(s_app_memory_block_manager, s_app_block_info_manager, s_app_page_table_manager);
|
||||
s_sys_system_resource.SetManagers(s_sys_memory_block_manager, s_sys_block_info_manager, s_sys_page_table_manager);
|
||||
}
|
||||
|
||||
void Kernel::PrintLayout() {
|
||||
@@ -135,6 +146,9 @@ namespace ams::kern {
|
||||
PrintMemoryRegion(" KernelRegion", KMemoryLayout::GetKernelRegionPhysicalExtents());
|
||||
PrintMemoryRegion(" Code", KMemoryLayout::GetKernelCodeRegionPhysicalExtents());
|
||||
PrintMemoryRegion(" Slab", KMemoryLayout::GetKernelSlabRegionPhysicalExtents());
|
||||
if constexpr (KSystemControl::SecureAppletMemorySize > 0) {
|
||||
PrintMemoryRegion(" SecureApplet", KMemoryLayout::GetKernelSecureAppletMemoryRegionPhysicalExtents());
|
||||
}
|
||||
PrintMemoryRegion(" PageTableHeap", KMemoryLayout::GetKernelPageTableHeapRegionPhysicalExtents());
|
||||
PrintMemoryRegion(" InitPageTable", KMemoryLayout::GetKernelInitPageTableRegionPhysicalExtents());
|
||||
if constexpr (IsKTraceEnabled) {
|
||||
|
||||
@@ -58,7 +58,6 @@ namespace ams::kern {
|
||||
MESOSPHERE_ABORT_UNLESS(management_region.GetEndAddress() != 0);
|
||||
|
||||
Kernel::GetMemoryManager().Initialize(management_region.GetAddress(), management_region.GetSize());
|
||||
init::InitializeKPageBufferSlabHeap();
|
||||
}
|
||||
|
||||
/* Copy the Initial Process Binary to safe memory. */
|
||||
|
||||
@@ -80,7 +80,12 @@ namespace ams::kern::svc {
|
||||
}
|
||||
}
|
||||
|
||||
Result MapDeviceAddressSpaceByForce(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||
Result MapDeviceAddressSpaceByForce(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, u32 option) {
|
||||
/* Decode the option. */
|
||||
const util::BitPack32 option_pack = { option };
|
||||
const auto device_perm = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Permission>();
|
||||
const auto reserved = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Reserved>();
|
||||
|
||||
/* Validate input. */
|
||||
R_UNLESS(util::IsAligned(process_address, PageSize), svc::ResultInvalidAddress());
|
||||
R_UNLESS(util::IsAligned(device_address, PageSize), svc::ResultInvalidAddress());
|
||||
@@ -90,6 +95,7 @@ namespace ams::kern::svc {
|
||||
R_UNLESS((device_address < device_address + size), svc::ResultInvalidMemoryRegion());
|
||||
R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS(IsValidDeviceMemoryPermission(device_perm), svc::ResultInvalidNewMemoryPermission());
|
||||
R_UNLESS(reserved == 0, svc::ResultInvalidEnumValue());
|
||||
|
||||
/* Get the device address space. */
|
||||
KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject<KDeviceAddressSpace>(das_handle);
|
||||
@@ -104,10 +110,15 @@ namespace ams::kern::svc {
|
||||
R_UNLESS(page_table.Contains(process_address, size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Map. */
|
||||
R_RETURN(das->MapByForce(std::addressof(page_table), KProcessAddress(process_address), size, device_address, device_perm));
|
||||
R_RETURN(das->MapByForce(std::addressof(page_table), KProcessAddress(process_address), size, device_address, option));
|
||||
}
|
||||
|
||||
Result MapDeviceAddressSpaceAligned(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||
Result MapDeviceAddressSpaceAligned(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, u32 option) {
|
||||
/* Decode the option. */
|
||||
const util::BitPack32 option_pack = { option };
|
||||
const auto device_perm = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Permission>();
|
||||
const auto reserved = option_pack.Get<ams::svc::MapDeviceAddressSpaceOption::Reserved>();
|
||||
|
||||
/* Validate input. */
|
||||
R_UNLESS(util::IsAligned(process_address, PageSize), svc::ResultInvalidAddress());
|
||||
R_UNLESS(util::IsAligned(device_address, PageSize), svc::ResultInvalidAddress());
|
||||
@@ -118,6 +129,7 @@ namespace ams::kern::svc {
|
||||
R_UNLESS((device_address < device_address + size), svc::ResultInvalidMemoryRegion());
|
||||
R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS(IsValidDeviceMemoryPermission(device_perm), svc::ResultInvalidNewMemoryPermission());
|
||||
R_UNLESS(reserved == 0, svc::ResultInvalidEnumValue());
|
||||
|
||||
/* Get the device address space. */
|
||||
KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject<KDeviceAddressSpace>(das_handle);
|
||||
@@ -132,7 +144,7 @@ namespace ams::kern::svc {
|
||||
R_UNLESS(page_table.Contains(process_address, size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Map. */
|
||||
R_RETURN(das->MapAligned(std::addressof(page_table), KProcessAddress(process_address), size, device_address, device_perm));
|
||||
R_RETURN(das->MapAligned(std::addressof(page_table), KProcessAddress(process_address), size, device_address, option));
|
||||
}
|
||||
|
||||
Result UnmapDeviceAddressSpace(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address) {
|
||||
@@ -176,12 +188,12 @@ namespace ams::kern::svc {
|
||||
R_RETURN(DetachDeviceAddressSpace(device_name, das_handle));
|
||||
}
|
||||
|
||||
Result MapDeviceAddressSpaceByForce64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||
R_RETURN(MapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, device_perm));
|
||||
Result MapDeviceAddressSpaceByForce64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) {
|
||||
R_RETURN(MapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, option));
|
||||
}
|
||||
|
||||
Result MapDeviceAddressSpaceAligned64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||
R_RETURN(MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, device_perm));
|
||||
Result MapDeviceAddressSpaceAligned64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) {
|
||||
R_RETURN(MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, option));
|
||||
}
|
||||
|
||||
Result UnmapDeviceAddressSpace64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address) {
|
||||
@@ -202,12 +214,12 @@ namespace ams::kern::svc {
|
||||
R_RETURN(DetachDeviceAddressSpace(device_name, das_handle));
|
||||
}
|
||||
|
||||
Result MapDeviceAddressSpaceByForce64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||
R_RETURN(MapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, device_perm));
|
||||
Result MapDeviceAddressSpaceByForce64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) {
|
||||
R_RETURN(MapDeviceAddressSpaceByForce(das_handle, process_handle, process_address, size, device_address, option));
|
||||
}
|
||||
|
||||
Result MapDeviceAddressSpaceAligned64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||
R_RETURN(MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, device_perm));
|
||||
Result MapDeviceAddressSpaceAligned64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, u32 option) {
|
||||
R_RETURN(MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, option));
|
||||
}
|
||||
|
||||
Result UnmapDeviceAddressSpace64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address) {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 <mesosphere.hpp>
|
||||
|
||||
namespace ams::kern::svc {
|
||||
|
||||
/* ============================= Common ============================= */
|
||||
|
||||
namespace {
|
||||
|
||||
Result MapInsecureMemory(uintptr_t address, size_t size) {
|
||||
/* Validate the address/size. */
|
||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||
R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress());
|
||||
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Verify that the mapping is in range. */
|
||||
auto &pt = GetCurrentProcess().GetPageTable();
|
||||
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_Insecure), svc::ResultInvalidMemoryRegion());
|
||||
|
||||
/* Map the insecure memory. */
|
||||
R_RETURN(pt.MapInsecureMemory(address, size));
|
||||
}
|
||||
|
||||
Result UnmapInsecureMemory(uintptr_t address, size_t size) {
|
||||
/* Validate the address/size. */
|
||||
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||
R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress());
|
||||
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Verify that the mapping is in range. */
|
||||
auto &pt = GetCurrentProcess().GetPageTable();
|
||||
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_Insecure), svc::ResultInvalidMemoryRegion());
|
||||
|
||||
/* Map the insecure memory. */
|
||||
R_RETURN(pt.UnmapInsecureMemory(address, size));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ============================= 64 ABI ============================= */
|
||||
|
||||
Result MapInsecureMemory64(ams::svc::Address address, ams::svc::Size size) {
|
||||
R_RETURN(MapInsecureMemory(address, size));
|
||||
}
|
||||
|
||||
Result UnmapInsecureMemory64(ams::svc::Address address, ams::svc::Size size) {
|
||||
R_RETURN(UnmapInsecureMemory(address, size));
|
||||
}
|
||||
|
||||
/* ============================= 64From32 ABI ============================= */
|
||||
|
||||
Result MapInsecureMemory64From32(ams::svc::Address address, ams::svc::Size size) {
|
||||
R_RETURN(MapInsecureMemory(address, size));
|
||||
}
|
||||
|
||||
Result UnmapInsecureMemory64From32(ams::svc::Address address, ams::svc::Size size) {
|
||||
R_RETURN(UnmapInsecureMemory(address, size));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -55,7 +55,7 @@ namespace ams::ddsf {
|
||||
|
||||
/* Attach the session. */
|
||||
m_session_list.push_back(*session);
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void DetachSession(ISession *session) {
|
||||
@@ -113,12 +113,12 @@ namespace ams::ddsf {
|
||||
|
||||
template<typename F>
|
||||
Result ForEachSession(F f, bool return_on_fail) {
|
||||
return impl::ForEach(m_session_list_lock, m_session_list, f, return_on_fail);
|
||||
R_RETURN(impl::ForEach(m_session_list_lock, m_session_list, f, return_on_fail));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
Result ForEachSession(F f, bool return_on_fail) const {
|
||||
return impl::ForEach(m_session_list_lock, m_session_list, f, return_on_fail);
|
||||
R_RETURN(impl::ForEach(m_session_list_lock, m_session_list, f, return_on_fail));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
|
||||
@@ -76,12 +76,12 @@ namespace ams::ddsf {
|
||||
|
||||
template<typename F>
|
||||
Result ForEachDevice(F f, bool return_on_fail) {
|
||||
return impl::ForEach(m_device_list_lock, m_device_list, f, return_on_fail);
|
||||
R_RETURN(impl::ForEach(m_device_list_lock, m_device_list, f, return_on_fail));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
Result ForEachDevice(F f, bool return_on_fail) const {
|
||||
return impl::ForEach(m_device_list_lock, m_device_list, f, return_on_fail);
|
||||
R_RETURN(impl::ForEach(m_device_list_lock, m_device_list, f, return_on_fail));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
|
||||
@@ -26,13 +26,13 @@ namespace ams::ddsf::impl {
|
||||
for (auto && it : list) {
|
||||
if (const auto cur_result = f(std::addressof(it)); R_FAILED(cur_result)) {
|
||||
if (return_on_fail) {
|
||||
return cur_result;
|
||||
R_RETURN(cur_result);
|
||||
} else if (R_SUCCEEDED(result)) {
|
||||
result = cur_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
R_RETURN(result);
|
||||
}
|
||||
|
||||
template<typename List, typename F, typename Lock>
|
||||
|
||||
@@ -832,4 +832,12 @@
|
||||
HANDLER(FatFsBisUserDirectoryPeakOpenCount, 653, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(FatFsSdCardFilePeakOpenCount, 654, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(FatFsSdCardDirectoryPeakOpenCount, 655, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(SslAlertInfo, 656, NetworkSecurityCertificateInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(SslVersionInfo, 657, NetworkSecurityCertificateInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||
HANDLER(FatFsBisSystemUniqueFileEntryPeakOpenCount, 658, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(FatFsBisSystemUniqueDirectoryEntryPeakOpenCount, 659, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(FatFsBisUserUniqueFileEntryPeakOpenCount, 660, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(FatFsBisUserUniqueDirectoryEntryPeakOpenCount, 661, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(FatFsSdCardUniqueFileEntryPeakOpenCount, 662, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
HANDLER(FatFsSdCardUniqueDirectoryEntryPeakOpenCount, 663, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <stratosphere/fs/fsa/fs_registrar.hpp>
|
||||
#include <stratosphere/fs/fs_remote_filesystem.hpp>
|
||||
#include <stratosphere/fs/fs_read_only_filesystem.hpp>
|
||||
#include <stratosphere/fs/fs_shared_filesystem_holder.hpp>
|
||||
#include <stratosphere/fs/fs_istorage.hpp>
|
||||
#include <stratosphere/fs/fs_i_event_notifier.hpp>
|
||||
#include <stratosphere/fs/fs_substorage.hpp>
|
||||
@@ -66,4 +65,5 @@
|
||||
#include <stratosphere/fs/fs_program_index_map_info.hpp>
|
||||
#include <stratosphere/fs/impl/fs_access_log_impl.hpp>
|
||||
#include <stratosphere/fs/impl/fs_hash_generator_factory_selector.hpp>
|
||||
#include <stratosphere/fs/impl/fs_storage_service_object_adapter.hpp>
|
||||
#include <stratosphere/fs/fs_api.hpp>
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
/* ACCURATE_TO_VERSION: 14.3.0.0 */
|
||||
class HierarchicalRomFileTable {
|
||||
public:
|
||||
using Position = u32;
|
||||
using Position = u32;
|
||||
using StorageSizeType = u32;
|
||||
|
||||
struct FindPosition {
|
||||
Position next_dir;
|
||||
@@ -30,8 +32,7 @@ namespace ams::fs {
|
||||
};
|
||||
static_assert(util::is_pod<FindPosition>::value);
|
||||
|
||||
using DirectoryInfo = RomDirectoryInfo;
|
||||
using FileInfo = RomFileInfo;
|
||||
using FileInfo = RomFileInfo;
|
||||
|
||||
static constexpr RomFileId PositionToFileId(Position pos) {
|
||||
return static_cast<RomFileId>(pos);
|
||||
@@ -80,23 +81,23 @@ namespace ams::fs {
|
||||
using Base = KeyValueRomStorageTemplate<ImplKeyType, ValueType, MaxKeyLength>;
|
||||
public:
|
||||
Result Add(Position *out, const ClientKeyType &key, const Value &value) {
|
||||
return Base::AddInternal(out, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar), value);
|
||||
R_RETURN(Base::AddInternal(out, key.key, key.Hash(), key.name.begin(), key.name.length(), value));
|
||||
}
|
||||
|
||||
Result Get(Position *out_pos, Value *out_val, const ClientKeyType &key) {
|
||||
return Base::GetInternal(out_pos, out_val, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar));
|
||||
R_RETURN(Base::GetInternal(out_pos, out_val, key.key, key.Hash(), key.name.begin(), key.name.length()));
|
||||
}
|
||||
|
||||
Result GetByPosition(ImplKey *out_key, Value *out_val, Position pos) {
|
||||
return Base::GetByPosition(out_key, out_val, pos);
|
||||
R_RETURN(Base::GetByPosition(out_key, out_val, pos));
|
||||
}
|
||||
|
||||
Result GetByPosition(ImplKey *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) {
|
||||
return Base::GetByPosition(out_key, out_val, out_aux, out_aux_size, pos);
|
||||
R_RETURN(Base::GetByPosition(out_key, out_val, out_aux, out_aux_size, pos));
|
||||
}
|
||||
|
||||
Result SetByPosition(Position pos, const Value &value) {
|
||||
return Base::SetByPosition(pos, value);
|
||||
R_RETURN(Base::SetByPosition(pos, value));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -121,16 +122,15 @@ namespace ams::fs {
|
||||
|
||||
constexpr u32 Hash() const {
|
||||
u32 hash = this->key.parent ^ 123456789;
|
||||
const RomPathChar * name = this->name.path;
|
||||
const RomPathChar * const end = name + this->name.length;
|
||||
while (name < end) {
|
||||
const u32 cur = static_cast<u32>(static_cast<std::make_unsigned<RomPathChar>::type>(*(name++)));
|
||||
hash = ((hash >> 5) | (hash << 27)) ^ cur;
|
||||
const RomPathChar * cur = this->name.begin();
|
||||
const RomPathChar * const end = this->name.end();
|
||||
while (cur < end) {
|
||||
const u32 c = static_cast<u32>(static_cast<std::make_unsigned<RomPathChar>::type>(*(cur++)));
|
||||
hash = ((hash >> 5) | (hash << 27)) ^ c;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<EntryKey>::value);
|
||||
|
||||
using DirectoryEntryMapTable = EntryMapTable<RomEntryKey, EntryKey, RomDirectoryEntry>;
|
||||
using FileEntryMapTable = EntryMapTable<RomEntryKey, EntryKey, RomFileEntry>;
|
||||
@@ -138,35 +138,24 @@ namespace ams::fs {
|
||||
DirectoryEntryMapTable m_dir_table;
|
||||
FileEntryMapTable m_file_table;
|
||||
public:
|
||||
static s64 QueryDirectoryEntryBucketStorageSize(s64 count);
|
||||
static size_t QueryDirectoryEntrySize(size_t aux_size);
|
||||
static s64 QueryFileEntryBucketStorageSize(s64 count);
|
||||
static size_t QueryFileEntrySize(size_t aux_size);
|
||||
static s64 QueryDirectoryEntryBucketStorageSize(StorageSizeType count);
|
||||
static s64 QueryDirectoryEntrySize(StorageSizeType aux_size);
|
||||
static s64 QueryFileEntryBucketStorageSize(StorageSizeType count);
|
||||
static s64 QueryFileEntrySize(StorageSizeType aux_size);
|
||||
|
||||
static Result Format(SubStorage dir_bucket, SubStorage file_bucket);
|
||||
public:
|
||||
HierarchicalRomFileTable();
|
||||
|
||||
constexpr u32 GetDirectoryEntryCount() const {
|
||||
return m_dir_table.GetEntryCount();
|
||||
}
|
||||
|
||||
constexpr u32 GetFileEntryCount() const {
|
||||
return m_file_table.GetEntryCount();
|
||||
}
|
||||
|
||||
Result Initialize(SubStorage dir_bucket, SubStorage dir_entry, SubStorage file_bucket, SubStorage file_entry);
|
||||
void Finalize();
|
||||
|
||||
Result CreateRootDirectory();
|
||||
Result CreateDirectory(RomDirectoryId *out, const RomPathChar *path, const DirectoryInfo &info);
|
||||
Result CreateDirectory(RomDirectoryId *out, const RomPathChar *path);
|
||||
Result CreateFile(RomFileId *out, const RomPathChar *path, const FileInfo &info);
|
||||
Result ConvertPathToDirectoryId(RomDirectoryId *out, const RomPathChar *path);
|
||||
Result ConvertPathToFileId(RomFileId *out, const RomPathChar *path);
|
||||
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, const RomPathChar *path);
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, RomDirectoryId id);
|
||||
|
||||
Result OpenFile(FileInfo *out, const RomPathChar *path);
|
||||
Result OpenFile(FileInfo *out, RomFileId id);
|
||||
|
||||
@@ -178,7 +167,7 @@ namespace ams::fs {
|
||||
|
||||
Result QueryRomFileSystemSize(s64 *out_dir_entry_size, s64 *out_file_entry_size);
|
||||
private:
|
||||
Result GetGrandParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path);
|
||||
Result GetParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path);
|
||||
|
||||
Result FindParentDirectoryRecursive(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, RomPathTool::PathParser *parser, const RomPathChar *path);
|
||||
|
||||
@@ -194,8 +183,6 @@ namespace ams::fs {
|
||||
Result GetFileEntry(Position *out_pos, RomFileEntry *out_entry, const EntryKey &key);
|
||||
Result GetFileEntry(RomFileEntry *out_entry, RomFileId id);
|
||||
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, const EntryKey &key);
|
||||
|
||||
Result OpenFile(FileInfo *out, const EntryKey &key);
|
||||
|
||||
Result FindOpen(FindPosition *out, const EntryKey &key);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
/* ACCURATE_TO_VERSION: 14.3.0.0 */
|
||||
template<typename KeyType, typename ValueType, size_t MaxAuxiliarySize>
|
||||
class KeyValueRomStorageTemplate {
|
||||
public:
|
||||
@@ -27,6 +28,8 @@ namespace ams::fs {
|
||||
using Position = u32;
|
||||
using BucketIndex = s64;
|
||||
|
||||
using StorageSizeType = u32;
|
||||
|
||||
struct FindIndex {
|
||||
BucketIndex ind;
|
||||
Position pos;
|
||||
@@ -39,7 +42,7 @@ namespace ams::fs {
|
||||
Key key;
|
||||
Value value;
|
||||
Position next;
|
||||
u32 size;
|
||||
StorageSizeType size;
|
||||
};
|
||||
static_assert(util::is_pod<Element>::value);
|
||||
private:
|
||||
@@ -53,53 +56,41 @@ namespace ams::fs {
|
||||
return num * sizeof(Position);
|
||||
}
|
||||
|
||||
static constexpr s64 QueryBucketCount(s64 size) {
|
||||
static constexpr s64 QueryBucketCount(StorageSizeType size) {
|
||||
return size / sizeof(Position);
|
||||
}
|
||||
|
||||
static constexpr size_t QueryEntrySize(size_t aux_size) {
|
||||
return util::AlignUp(sizeof(Element) + aux_size, alignof(Element));
|
||||
static constexpr size_t QueryEntrySize(StorageSizeType aux_size) {
|
||||
return util::AlignUp<size_t>(sizeof(Element) + aux_size, alignof(Element));
|
||||
}
|
||||
|
||||
static Result Format(SubStorage bucket, s64 count) {
|
||||
static Result Format(SubStorage bucket, StorageSizeType count) {
|
||||
const Position pos = InvalidPosition;
|
||||
for (s64 i = 0; i < count; i++) {
|
||||
for (auto i = 0u; i < count; i++) {
|
||||
R_TRY(bucket.Write(i * sizeof(pos), std::addressof(pos), sizeof(pos)));
|
||||
}
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
public:
|
||||
KeyValueRomStorageTemplate() : m_bucket_count(), m_bucket_storage(), m_kv_storage(), m_total_entry_size(), m_entry_count() { /* ... */ }
|
||||
constexpr KeyValueRomStorageTemplate() : m_bucket_count(), m_bucket_storage(), m_kv_storage(), m_total_entry_size(), m_entry_count() { /* ... */ }
|
||||
|
||||
Result Initialize(const SubStorage &bucket, s64 count, const SubStorage &kv) {
|
||||
AMS_ASSERT(count > 0);
|
||||
m_bucket_storage = bucket;
|
||||
m_bucket_count = count;
|
||||
m_kv_storage = kv;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
m_bucket_storage = SubStorage();
|
||||
m_kv_storage = SubStorage();
|
||||
m_bucket_count = 0;
|
||||
m_kv_storage = SubStorage();
|
||||
}
|
||||
|
||||
s64 GetTotalEntrySize() const {
|
||||
return m_total_entry_size;
|
||||
}
|
||||
|
||||
Result GetFreeSize(s64 *out) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
s64 kv_size = 0;
|
||||
R_TRY(m_kv_storage.GetSize(std::addressof(kv_size)));
|
||||
*out = kv_size - m_total_entry_size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
constexpr u32 GetEntryCount() const {
|
||||
return m_entry_count;
|
||||
}
|
||||
protected:
|
||||
Result AddInternal(Position *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
@@ -116,18 +107,18 @@ namespace ams::fs {
|
||||
}
|
||||
|
||||
Position pos;
|
||||
R_TRY(this->AllocateEntry(std::addressof(pos), aux_size));
|
||||
R_TRY(this->AllocateEntry(std::addressof(pos), static_cast<StorageSizeType>(aux_size)));
|
||||
|
||||
Position next_pos;
|
||||
R_TRY(this->LinkEntry(std::addressof(next_pos), pos, hash_key));
|
||||
|
||||
const Element elem = { key, value, next_pos, static_cast<u32>(aux_size) };
|
||||
const Element elem = { key, value, next_pos, static_cast<StorageSizeType>(aux_size) };
|
||||
R_TRY(this->WriteKeyValue(std::addressof(elem), pos, aux, aux_size));
|
||||
|
||||
*out = pos;
|
||||
m_entry_count++;
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetInternal(Position *out_pos, Value *out_val, const Key &key, u32 hash_key, const void *aux, size_t aux_size) {
|
||||
@@ -141,7 +132,7 @@ namespace ams::fs {
|
||||
|
||||
*out_pos = pos;
|
||||
*out_val = elem.value;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetByPosition(Key *out_key, Value *out_val, Position pos) {
|
||||
@@ -153,7 +144,7 @@ namespace ams::fs {
|
||||
|
||||
*out_key = elem.key;
|
||||
*out_val = elem.value;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetByPosition(Key *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) {
|
||||
@@ -167,14 +158,14 @@ namespace ams::fs {
|
||||
|
||||
*out_key = elem.key;
|
||||
*out_val = elem.value;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result SetByPosition(Position pos, const Value &value) {
|
||||
Element elem;
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), pos));
|
||||
elem.value = value;
|
||||
return this->WriteKeyValue(std::addressof(elem), pos, nullptr, 0);
|
||||
R_RETURN(this->WriteKeyValue(std::addressof(elem), pos, nullptr, 0));
|
||||
}
|
||||
private:
|
||||
BucketIndex HashToBucket(u32 hash_key) const {
|
||||
@@ -202,17 +193,16 @@ namespace ams::fs {
|
||||
|
||||
R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound());
|
||||
|
||||
u8 *buf = static_cast<u8 *>(::ams::fs::impl::Allocate(MaxAuxiliarySize));
|
||||
R_UNLESS(buf != nullptr, fs::ResultAllocationMemoryFailedInDbmRomKeyValueStorage());
|
||||
ON_SCOPE_EXIT { ::ams::fs::impl::Deallocate(buf, MaxAuxiliarySize); };
|
||||
auto buf = ::ams::fs::impl::MakeUnique<u8[]>(MaxAuxiliarySize);
|
||||
R_UNLESS(buf != nullptr, fs::ResultAllocationMemoryFailedMakeUnique());
|
||||
|
||||
while (true) {
|
||||
size_t cur_aux_size;
|
||||
R_TRY(this->ReadKeyValue(out_elem, buf, std::addressof(cur_aux_size), cur));
|
||||
R_TRY(this->ReadKeyValue(out_elem, buf.get(), std::addressof(cur_aux_size), cur));
|
||||
|
||||
if (key.IsEqual(out_elem->key, aux, aux_size, buf, cur_aux_size)) {
|
||||
if (key.IsEqual(out_elem->key, aux, aux_size, buf.get(), cur_aux_size)) {
|
||||
*out_pos = cur;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
*out_prev = cur;
|
||||
@@ -221,18 +211,18 @@ namespace ams::fs {
|
||||
}
|
||||
}
|
||||
|
||||
Result AllocateEntry(Position *out, size_t aux_size) {
|
||||
Result AllocateEntry(Position *out, StorageSizeType aux_size) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(m_kv_storage.GetSize(std::addressof(kv_size)));
|
||||
const size_t end_pos = m_total_entry_size + sizeof(Element) + aux_size;
|
||||
const size_t end_pos = m_total_entry_size + sizeof(Element) + static_cast<size_t>(aux_size);
|
||||
R_UNLESS(end_pos <= static_cast<size_t>(kv_size), fs::ResultDbmKeyFull());
|
||||
|
||||
*out = static_cast<Position>(m_total_entry_size);
|
||||
|
||||
m_total_entry_size = util::AlignUp(static_cast<s64>(end_pos), alignof(Position));
|
||||
return ResultSuccess();
|
||||
m_total_entry_size = util::AlignUp<s64>(static_cast<s64>(end_pos), alignof(Position));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result LinkEntry(Position *out, Position pos, u32 hash_key) {
|
||||
@@ -250,7 +240,7 @@ namespace ams::fs {
|
||||
R_TRY(this->WriteBucket(pos, ind));
|
||||
|
||||
*out = next;
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ReadBucket(Position *out, BucketIndex ind) {
|
||||
@@ -258,14 +248,14 @@ namespace ams::fs {
|
||||
AMS_ASSERT(ind < m_bucket_count);
|
||||
|
||||
const s64 offset = ind * sizeof(Position);
|
||||
return m_bucket_storage.Read(offset, out, sizeof(*out));
|
||||
R_RETURN(m_bucket_storage.Read(offset, out, sizeof(*out)));
|
||||
}
|
||||
|
||||
Result WriteBucket(Position pos, BucketIndex ind) {
|
||||
AMS_ASSERT(ind < m_bucket_count);
|
||||
|
||||
const s64 offset = ind * sizeof(Position);
|
||||
return m_bucket_storage.Write(offset, std::addressof(pos), sizeof(pos));
|
||||
R_RETURN(m_bucket_storage.Write(offset, std::addressof(pos), sizeof(pos)));
|
||||
}
|
||||
|
||||
Result ReadKeyValue(Element *out, Position pos) {
|
||||
@@ -275,7 +265,7 @@ namespace ams::fs {
|
||||
R_TRY(m_kv_storage.GetSize(std::addressof(kv_size)));
|
||||
AMS_ASSERT(pos < kv_size);
|
||||
|
||||
return m_kv_storage.Read(pos, out, sizeof(*out));
|
||||
R_RETURN(m_kv_storage.Read(pos, out, sizeof(*out)));
|
||||
}
|
||||
|
||||
Result ReadKeyValue(Element *out, void *out_aux, size_t *out_aux_size, Position pos) {
|
||||
@@ -290,7 +280,7 @@ namespace ams::fs {
|
||||
R_TRY(m_kv_storage.Read(pos + sizeof(*out), out_aux, out->size));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result WriteKeyValue(const Element *elem, Position pos, const void *aux, size_t aux_size) {
|
||||
@@ -307,7 +297,7 @@ namespace ams::fs {
|
||||
R_TRY(m_kv_storage.Write(pos + sizeof(*elem), aux, aux_size));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -18,34 +18,60 @@
|
||||
|
||||
namespace ams::fs::RomPathTool {
|
||||
|
||||
/* ACCURATE_TO_VERSION: 14.3.0.0 */
|
||||
|
||||
constexpr inline u32 MaxPathLength = 0x300;
|
||||
|
||||
struct RomEntryName {
|
||||
size_t length;
|
||||
const RomPathChar *path;
|
||||
};
|
||||
static_assert(util::is_pod<RomEntryName>::value);
|
||||
|
||||
constexpr void InitEntryName(RomEntryName *entry) {
|
||||
AMS_ASSERT(entry != nullptr);
|
||||
entry->length = 0;
|
||||
}
|
||||
|
||||
constexpr inline bool IsSeparator(RomPathChar c) {
|
||||
constexpr ALWAYS_INLINE bool IsSeparator(RomPathChar c) {
|
||||
return c == RomStringTraits::DirectorySeparator;
|
||||
}
|
||||
|
||||
constexpr inline bool IsNullTerminator(RomPathChar c) {
|
||||
constexpr ALWAYS_INLINE bool IsNullTerminator(RomPathChar c) {
|
||||
return c == RomStringTraits::NullTerminator;
|
||||
}
|
||||
|
||||
constexpr inline bool IsDot(RomPathChar c) {
|
||||
constexpr ALWAYS_INLINE bool IsDot(RomPathChar c) {
|
||||
return c == RomStringTraits::Dot;
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomEntryName &name) {
|
||||
return name.length == 1 && IsDot(name.path[0]);
|
||||
}
|
||||
class RomEntryName {
|
||||
private:
|
||||
const RomPathChar *m_path;
|
||||
size_t m_length;
|
||||
public:
|
||||
constexpr RomEntryName() : m_path(nullptr), m_length(0) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr void Initialize(const RomPathChar *p, size_t len) {
|
||||
m_path = p;
|
||||
m_length = len;
|
||||
}
|
||||
|
||||
constexpr bool IsCurrentDirectory() const {
|
||||
return m_length == 1 && IsDot(m_path[0]);
|
||||
}
|
||||
|
||||
constexpr bool IsParentDirectory() const {
|
||||
return m_length == 2 && IsDot(m_path[0]) && IsDot(m_path[1]);
|
||||
}
|
||||
|
||||
constexpr bool IsRootDirectory() const {
|
||||
return m_length == 0;
|
||||
}
|
||||
|
||||
constexpr const RomPathChar *begin() const {
|
||||
return m_path;
|
||||
}
|
||||
|
||||
constexpr const RomPathChar *end() const {
|
||||
return m_path + m_length;
|
||||
}
|
||||
|
||||
constexpr size_t length() const {
|
||||
return m_length;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomPathChar *p, size_t length) {
|
||||
AMS_ASSERT(p != nullptr);
|
||||
@@ -57,10 +83,6 @@ namespace ams::fs::RomPathTool {
|
||||
return IsDot(p[0]) && IsNullTerminator(p[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomEntryName &name) {
|
||||
return name.length == 2 && IsDot(name.path[0]) && IsDot(name.path[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomPathChar *p) {
|
||||
AMS_ASSERT(p != nullptr);
|
||||
return IsDot(p[0]) && IsDot(p[1]) && IsNullTerminator(p[2]);
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
/* ACCURATE_TO_VERSION: 14.3.0.0 */
|
||||
using RomPathChar = char;
|
||||
using RomFileId = s32;
|
||||
using RomDirectoryId = s32;
|
||||
using RomFileId = u32;
|
||||
using RomDirectoryId = u32;
|
||||
|
||||
struct RomFileSystemInformation {
|
||||
s64 size;
|
||||
@@ -37,11 +38,6 @@ namespace ams::fs {
|
||||
static_assert(util::is_pod<RomFileSystemInformation>::value);
|
||||
static_assert(sizeof(RomFileSystemInformation) == 0x50);
|
||||
|
||||
struct RomDirectoryInfo {
|
||||
/* ... */
|
||||
};
|
||||
static_assert(util::is_pod<RomDirectoryInfo>::value);
|
||||
|
||||
struct RomFileInfo {
|
||||
Int64 offset;
|
||||
Int64 size;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
/* ACCURATE_TO_VERSION: 13.4.0.0 */
|
||||
class DirectoryPathParser {
|
||||
NON_COPYABLE(DirectoryPathParser);
|
||||
NON_MOVEABLE(DirectoryPathParser);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
/* ACCURATE_TO_VERSION: Unknown */
|
||||
class FileStorage : public IStorage, public impl::Newable {
|
||||
NON_COPYABLE(FileStorage);
|
||||
NON_MOVEABLE(FileStorage);
|
||||
@@ -74,6 +75,7 @@ namespace ams::fs {
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
|
||||
};
|
||||
|
||||
/* ACCURATE_TO_VERSION: Unknown */
|
||||
class FileStorageBasedFileSystem : public FileStorage {
|
||||
NON_COPYABLE(FileStorageBasedFileSystem);
|
||||
NON_MOVEABLE(FileStorageBasedFileSystem);
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
/* ACCURATE_TO_VERSION: Unknown */
|
||||
|
||||
enum AccessLogMode : u32 {
|
||||
AccessLogMode_None = 0,
|
||||
AccessLogMode_Log = 1,
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
/* ACCURATE_TO_VERSION: Unknown */
|
||||
|
||||
void InitializeForSystem();
|
||||
void InitializeWithMultiSessionForSystem();
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
/* ACCURATE_TO_VERSION: Unknown */
|
||||
|
||||
Result MountApplicationPackage(const char *name, const char *common_path);
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
/* ACCURATE_TO_VERSION: Unknown */
|
||||
|
||||
enum class BisPartitionId {
|
||||
/* Boot0 */
|
||||
BootPartition1Root = 0,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user