Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85c23b5781 | ||
|
|
8e042f2262 | ||
|
|
81e9154a52 | ||
|
|
e9b9dbc2aa | ||
|
|
7e6c849ca4 | ||
|
|
8ec7c096d0 | ||
|
|
6e5b901a9b | ||
|
|
b800953d66 | ||
|
|
f0240db75a | ||
|
|
1f5ec68a5c | ||
|
|
ed9e60acb9 | ||
|
|
a7300b0fa4 | ||
|
|
8e2eca2004 | ||
|
|
9f83b3c838 | ||
|
|
434c8cefc4 | ||
|
|
d8aed7de6d | ||
|
|
a346014dc7 | ||
|
|
4b3c801e9f | ||
|
|
90db1223f6 | ||
|
|
fa64a6ff4d | ||
|
|
0c6a06a0cf | ||
|
|
5efb4a2a98 | ||
|
|
3b662122f9 | ||
|
|
e9b28ab4b1 | ||
|
|
1afb184c14 | ||
|
|
5e070600a9 | ||
|
|
8274081e39 | ||
|
|
f1ad26ce84 | ||
|
|
e4c314146e | ||
|
|
52f00731d9 | ||
|
|
476d658a79 | ||
|
|
7263022bac | ||
|
|
e0e7aa1e2f | ||
|
|
bd9d8fff46 | ||
|
|
61e3f0b391 | ||
|
|
cd9b173318 | ||
|
|
a8df400825 | ||
|
|
68040e2922 | ||
|
|
8da4d14e15 | ||
|
|
e2ebf9c0ff | ||
|
|
5fb6f52b9e | ||
|
|
982389dceb | ||
|
|
f636596ee2 | ||
|
|
0a2440522f | ||
|
|
3292ea5970 | ||
|
|
33d42f4831 | ||
|
|
46094cfb3e | ||
|
|
618691a500 | ||
|
|
356d89244f | ||
|
|
1ce3611695 | ||
|
|
1ab8b23444 | ||
|
|
06b4738d54 | ||
|
|
b92c614347 | ||
|
|
99175c1149 | ||
|
|
8876eedfb0 | ||
|
|
bbcee8c77c | ||
|
|
f7915c2c05 | ||
|
|
668cabd4a2 | ||
|
|
d64ab354ad | ||
|
|
59b518783d | ||
|
|
6462101b6f | ||
|
|
0ea5dbcfbb | ||
|
|
bb6446aada | ||
|
|
e46e7e0eb1 | ||
|
|
cb89c66bd8 | ||
|
|
e85a512cf4 | ||
|
|
7d9fea01c3 | ||
|
|
406320f6ec | ||
|
|
aad2be0a01 | ||
|
|
25383db524 | ||
|
|
48f4c526f3 | ||
|
|
1279d236f3 | ||
|
|
008eb974d4 | ||
|
|
035cebef9d | ||
|
|
8db22967bf | ||
|
|
db510f96c3 | ||
|
|
6e2dd791b2 | ||
|
|
bff61c68ab | ||
|
|
ca7734ffaf | ||
|
|
ed22f802ee | ||
|
|
8ffc177b44 | ||
|
|
c058376b3b | ||
|
|
d5ebf13094 | ||
|
|
695c125721 | ||
|
|
e7e3e7b374 | ||
|
|
3a5f406c5f | ||
|
|
8176f085f1 | ||
|
|
7a69f2f062 |
@@ -51,6 +51,8 @@ dist: dist-no-debug
|
|||||||
cp $(CURRENT_DIRECTORY)/stratosphere/spl/$(ATMOSPHERE_OUT_DIR)/spl.elf $(DIST_DIR)/spl.elf
|
cp $(CURRENT_DIRECTORY)/stratosphere/spl/$(ATMOSPHERE_OUT_DIR)/spl.elf $(DIST_DIR)/spl.elf
|
||||||
cp $(CURRENT_DIRECTORY)/stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.elf $(DIST_DIR)/TioServer.elf
|
cp $(CURRENT_DIRECTORY)/stratosphere/TioServer/$(ATMOSPHERE_OUT_DIR)/TioServer.elf $(DIST_DIR)/TioServer.elf
|
||||||
cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
|
cp $(CURRENT_DIRECTORY)/troposphere/daybreak/daybreak.elf $(DIST_DIR)/daybreak.elf
|
||||||
|
cp $(CURRENT_DIRECTORY)/troposphere/haze/haze.elf $(DIST_DIR)/haze.elf
|
||||||
|
cp $(CURRENT_DIRECTORY)/troposphere/reboot_to_payload/reboot_to_payload.elf $(DIST_DIR)/reboot_to_payload.elf
|
||||||
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
|
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION)-debug.zip ./*; cd ../;
|
||||||
rm -rf $(DIST_DIR)
|
rm -rf $(DIST_DIR)
|
||||||
|
|
||||||
@@ -106,6 +108,7 @@ dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
|
|||||||
rm -r $(DIST_DIR)/stratosphere_romfs
|
rm -r $(DIST_DIR)/stratosphere_romfs
|
||||||
cp troposphere/reboot_to_payload/reboot_to_payload.nro $(DIST_DIR)/switch/reboot_to_payload.nro
|
cp troposphere/reboot_to_payload/reboot_to_payload.nro $(DIST_DIR)/switch/reboot_to_payload.nro
|
||||||
cp troposphere/daybreak/daybreak.nro $(DIST_DIR)/switch/daybreak.nro
|
cp troposphere/daybreak/daybreak.nro $(DIST_DIR)/switch/daybreak.nro
|
||||||
|
cp troposphere/haze/haze.nro $(DIST_DIR)/switch/haze.nro
|
||||||
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION).zip ./*; cd ../;
|
cd $(DIST_DIR); zip -r ../atmosphere-$(ATMOSPHERE_VERSION).zip ./*; cd ../;
|
||||||
rm -rf $(DIST_DIR)
|
rm -rf $(DIST_DIR)
|
||||||
cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/fusee.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin
|
cp fusee/$(ATMOSPHERE_BOOT_OUT_DIR)/fusee.bin $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)/fusee.bin
|
||||||
|
|||||||
@@ -67,6 +67,10 @@
|
|||||||
; Note that this setting is ignored (and treated as 1) when htc is enabled.
|
; Note that this setting is ignored (and treated as 1) when htc is enabled.
|
||||||
; 0 = Disabled, 1 = Enabled
|
; 0 = Disabled, 1 = Enabled
|
||||||
; enable_log_manager = u8!0x0
|
; enable_log_manager = u8!0x0
|
||||||
|
; Controls whether the bluetooth pairing database is redirected to the SD card (shared across sysmmc/all emummcs)
|
||||||
|
; NOTE: On <13.0.0, the database size was 10 instead of 20; booting pre-13.0.0 will truncate the database.
|
||||||
|
; 0 = Disabled, 1 = Enabled
|
||||||
|
; enable_external_bluetooth_db = u8!0x0
|
||||||
[hbloader]
|
[hbloader]
|
||||||
; Controls the size of the homebrew heap when running as applet.
|
; Controls the size of the homebrew heap when running as applet.
|
||||||
; If set to zero, all available applet memory is used as heap.
|
; If set to zero, all available applet memory is used as heap.
|
||||||
|
|||||||
@@ -1,4 +1,43 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
## 1.5.3
|
||||||
|
+ Support was added for 16.0.3.
|
||||||
|
+ Atmosphère was updated to use GCC 13/newlib (latest devkitA64/devkitARM releases).
|
||||||
|
+ **Please note**: This introduces a known issue, which is currently being worked on.
|
||||||
|
+ As you may recall from the 1.4.1 changelog, Fire Emblem: Engage requires enormous amounts of memory to support using layeredfs mods with the game.
|
||||||
|
+ Latest GCC/newlib slightly increases malloc overhead size, which makes the previous memory increase insufficient.
|
||||||
|
+ A general-case solution to this is in the works, which should hopefully fix the problem in a way that doesn't jinx me for the future.
|
||||||
|
+ A number of minor issues were fixed and improvements were made, including:
|
||||||
|
+ An issue was fixed that caused system font replacement to not work on 16.0.0+.
|
||||||
|
+ An minor accuracy issue was addressed in mesosphere's management of certain memory ranges; this issue would have had zero visible impact to the end-user.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.5.2
|
||||||
|
+ A homebrew application (`haze`) was added for performing USB file transfer (with thanks to @liamwhite for both design and implementation).
|
||||||
|
+ `haze` is included with atmosphère, and provides access to the SD card via the PTP/MTP protocol.
|
||||||
|
+ **Please note**: haze will show inside the homebrew menu under the name "USB File Transfer".
|
||||||
|
+ **Please note**: Atmosphère cannot be updated at runtime, and trying to install an atmosphère update via haze will fail as usual.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.5.1
|
||||||
|
+ `fatal` was updated to reduce memory footprint.
|
||||||
|
+ Starting in 16.0.0, official `fatal` has no framebuffer or rendering logic, and instead calls other system service commands to draw the screen.
|
||||||
|
+ However, these commands aren't usable by atmosphère (too small rendering window, bad color support).
|
||||||
|
+ To reduce the relative memory footprint differential between atmosphère and official code, the framebuffer (2 MB) is now dynamically allocated when needed.
|
||||||
|
+ This will try to allocate from multiple pools (preferring System > System_NonSecure > Application).
|
||||||
|
+ This technically requires that 2 MB be available in at least one of these pools for the fatal screen to render (otherwise, a reboot-to-black-and-white-fatal will occur), but this should be a non-issue in almost all cases.
|
||||||
|
+ A feature was added to optionally mirror the bluetooth pairing database to the SD card (thanks @ndeadly).
|
||||||
|
+ This allows device pairings to be automatically kept in-sync across sysmmc/all emummcs.
|
||||||
|
+ This is opt-in, and can be controlled by setting `atmosphere!enable_external_bluetooth_db = u8!0x1`.
|
||||||
|
+ When enabled, the pairing database will be synchronized to `/atmosphere/bluetooth_devices.db`.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
## 1.5.0
|
||||||
|
+ Support was added for 16.0.0
|
||||||
|
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||||
|
+ `ncm` was updated to reflect the latest official behavior.
|
||||||
|
+ Many FS apis were updated under the hood to reflect the latest official behavior.
|
||||||
|
+ **Please Note**: 16.0.0 made breaking changes to a number of system APIs, including in FS/NCM/Shared Font commands that some homebrew programs may use.
|
||||||
|
+ These programs may encounter strange errors, and may need to be recompiled with a libnx updated to support 16.0.0's changes to function properly.
|
||||||
|
+ A number of minor issues were fixed and improvements were made, including:
|
||||||
|
+ An issue was fixed that could cause GPIO outputs to be misconfigured under certain circumstances.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
## 1.4.1
|
## 1.4.1
|
||||||
+ A number of minor issues were fixed and improvements were made, including:
|
+ A number of minor issues were fixed and improvements were made, including:
|
||||||
+ `dmnt` cheat toggle files are no longer ignored when they are missing a trailing newline.
|
+ `dmnt` cheat toggle files are no longer ignored when they are missing a trailing newline.
|
||||||
@@ -12,10 +51,11 @@
|
|||||||
+ The additional memory here is taken from the applet pool; no issues are expected to arise from this, but please report anything you may run into.
|
+ The additional memory here is taken from the applet pool; no issues are expected to arise from this, but please report anything you may run into.
|
||||||
+ As usual, if you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact `SciresM#0524`.
|
+ As usual, if you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact `SciresM#0524`.
|
||||||
+ I am jinxing myself by saying this, but it's really hard to imagine any game being worse than Fire Emblem: Engage, but if it happens again I will drop everything to fix it as usual.
|
+ I am jinxing myself by saying this, but it's really hard to imagine any game being worse than Fire Emblem: Engage, but if it happens again I will drop everything to fix it as usual.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
## 1.4.0
|
## 1.4.0
|
||||||
+ Support was added for 15.0.0.
|
+ Support was added for 15.0.0.
|
||||||
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
+ `mesosphère` was updated to reflect the latest official kernel behavior.
|
||||||
+ `ncm` was updated to reflect the latest official kernel behavior.
|
+ `ncm` was updated to reflect the latest official behavior.
|
||||||
+ A number of minor issues were fixed and improvements were made, including:
|
+ 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.
|
+ 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.
|
+ An off-by-one was fixed in mesosphere when computing the new value for an address arbiter signaled with ModifyByWaitingCountIfEqual.
|
||||||
|
|||||||
18
docs/faq.md
Normal file
18
docs/faq.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Frequently Asked Questions
|
||||||
|
|
||||||
|
This document serves as a place to store answers for common questions received about Atmosphère.
|
||||||
|
|
||||||
|
## What does "June 15th" mean?
|
||||||
|
When Atmosphère began development in February 2018, "June 15" was given as the estimate/target date for a first release, to coincide with the planned disclosure of a vulnerability.
|
||||||
|
|
||||||
|
This deadline was missed, hard.
|
||||||
|
|
||||||
|
People made rather a lot of fun of me (SciresM) for this.
|
||||||
|
|
||||||
|
Several months later, when the first Atmosphère release occurred, I captioned it "Happy June 15th!" and pretended like I hadn't missed the first deadline.
|
||||||
|
|
||||||
|
This amused me a lot, and so the practice has been kept up for every single release since.
|
||||||
|
|
||||||
|
Depending on who you ask, you may be told that this is a dumb joke and it is not funny.
|
||||||
|
|
||||||
|
This is incorrect. It is definitely a dumb joke, but it is also hilarious.
|
||||||
@@ -27,3 +27,6 @@ A list of planned features for Atmosphère can be found [here](roadmap.md).
|
|||||||
|
|
||||||
## Release History
|
## Release History
|
||||||
A changelog of previous versions of Atmosphère can be found [here](changelog.md).
|
A changelog of previous versions of Atmosphère can be found [here](changelog.md).
|
||||||
|
|
||||||
|
## Frequently Asked Questions
|
||||||
|
Answers to one or more frequently asked questions may be found [here](faq.md).
|
||||||
|
|||||||
4
emummc/.gitrepo
vendored
4
emummc/.gitrepo
vendored
@@ -6,7 +6,7 @@
|
|||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/m4xw/emummc
|
remote = https://github.com/m4xw/emummc
|
||||||
branch = develop
|
branch = develop
|
||||||
commit = 4714b2df9eaf68fb85516b35f7f4265ab0413825
|
commit = 30205111ee375bef96f0f76cb6a3130a2f0fc85c
|
||||||
parent = 99f6a96845b6097d50f5059eea9245d27876f26a
|
parent = 81e9154a52a976f85317bddd0131426599d26a62
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.4.1
|
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***
|
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
||||||
|
|
||||||
### Supported Horizon Versions
|
### Supported Horizon Versions
|
||||||
**1.0.0 - 15.0.0**
|
**1.0.0 - 16.0.3**
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Arbitrary SDMMC backend selection
|
* Arbitrary SDMMC backend selection
|
||||||
|
|||||||
16
emummc/source/FS/FS_offsets.c
vendored
16
emummc/source/FS/FS_offsets.c
vendored
@@ -63,6 +63,10 @@
|
|||||||
#include "offsets/1400_exfat.h"
|
#include "offsets/1400_exfat.h"
|
||||||
#include "offsets/1500.h"
|
#include "offsets/1500.h"
|
||||||
#include "offsets/1500_exfat.h"
|
#include "offsets/1500_exfat.h"
|
||||||
|
#include "offsets/1600.h"
|
||||||
|
#include "offsets/1600_exfat.h"
|
||||||
|
#include "offsets/1603.h"
|
||||||
|
#include "offsets/1603_exfat.h"
|
||||||
#include "../utils/fatal.h"
|
#include "../utils/fatal.h"
|
||||||
|
|
||||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
||||||
@@ -137,6 +141,10 @@ DEFINE_OFFSET_STRUCT(_1400);
|
|||||||
DEFINE_OFFSET_STRUCT(_1400_EXFAT);
|
DEFINE_OFFSET_STRUCT(_1400_EXFAT);
|
||||||
DEFINE_OFFSET_STRUCT(_1500);
|
DEFINE_OFFSET_STRUCT(_1500);
|
||||||
DEFINE_OFFSET_STRUCT(_1500_EXFAT);
|
DEFINE_OFFSET_STRUCT(_1500_EXFAT);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1600);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1600_EXFAT);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1603);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1603_EXFAT);
|
||||||
|
|
||||||
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
@@ -234,6 +242,14 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
|||||||
return &(GET_OFFSET_STRUCT_NAME(_1500));
|
return &(GET_OFFSET_STRUCT_NAME(_1500));
|
||||||
case FS_VER_15_0_0_EXFAT:
|
case FS_VER_15_0_0_EXFAT:
|
||||||
return &(GET_OFFSET_STRUCT_NAME(_1500_EXFAT));
|
return &(GET_OFFSET_STRUCT_NAME(_1500_EXFAT));
|
||||||
|
case FS_VER_16_0_0:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1600));
|
||||||
|
case FS_VER_16_0_0_EXFAT:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1600_EXFAT));
|
||||||
|
case FS_VER_16_0_3:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1603));
|
||||||
|
case FS_VER_16_0_3_EXFAT:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1603_EXFAT));
|
||||||
default:
|
default:
|
||||||
fatal_abort(Fatal_UnknownVersion);
|
fatal_abort(Fatal_UnknownVersion);
|
||||||
}
|
}
|
||||||
|
|||||||
6
emummc/source/FS/FS_versions.h
vendored
6
emummc/source/FS/FS_versions.h
vendored
@@ -92,6 +92,12 @@ enum FS_VER
|
|||||||
FS_VER_15_0_0,
|
FS_VER_15_0_0,
|
||||||
FS_VER_15_0_0_EXFAT,
|
FS_VER_15_0_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_16_0_0,
|
||||||
|
FS_VER_16_0_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_16_0_3,
|
||||||
|
FS_VER_16_0_3_EXFAT,
|
||||||
|
|
||||||
FS_VER_MAX,
|
FS_VER_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
59
emummc/source/FS/offsets/1600.h
vendored
Normal file
59
emummc/source/FS/offsets/1600.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_1600_H__
|
||||||
|
#define __FS_1600_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1600_SDMMC_ACCESSOR_GC 0x1862A0
|
||||||
|
#define FS_OFFSET_1600_SDMMC_ACCESSOR_SD 0x187F20
|
||||||
|
#define FS_OFFSET_1600_SDMMC_ACCESSOR_NAND 0x186760
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1600_SDMMC_WRAPPER_READ 0x1821F0
|
||||||
|
#define FS_OFFSET_1600_SDMMC_WRAPPER_WRITE 0x182250
|
||||||
|
#define FS_OFFSET_1600_RTLD 0x269B0
|
||||||
|
#define FS_OFFSET_1600_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1600_CLKRST_SET_MIN_V_CLK_RATE 0x1A2D30
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1600_LOCK_MUTEX 0x17B730
|
||||||
|
#define FS_OFFSET_1600_UNLOCK_MUTEX 0x17B780
|
||||||
|
|
||||||
|
#define FS_OFFSET_1600_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1821B0
|
||||||
|
#define FS_OFFSET_1600_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1821D0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1600_SD_MUTEX 0xFFB3F0
|
||||||
|
#define FS_OFFSET_1600_NAND_MUTEX 0xFF6B58
|
||||||
|
#define FS_OFFSET_1600_ACTIVE_PARTITION 0xFF6B98
|
||||||
|
#define FS_OFFSET_1600_SDMMC_DAS_HANDLE 0xFDC8B0
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1600_SD_DAS_INIT 0x258D4
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1600_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00063B48, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00070D6C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007790C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008A754, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1600_H__
|
||||||
59
emummc/source/FS/offsets/1600_exfat.h
vendored
Normal file
59
emummc/source/FS/offsets/1600_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_1600_EXFAT_H__
|
||||||
|
#define __FS_1600_EXFAT_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_GC 0x190F80
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_SD 0x192C00
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_ACCESSOR_NAND 0x191440
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_READ 0x18CED0
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_WRITE 0x18CF30
|
||||||
|
#define FS_OFFSET_1600_EXFAT_RTLD 0x269B0
|
||||||
|
#define FS_OFFSET_1600_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1600_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1ADA10
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1600_EXFAT_LOCK_MUTEX 0x186410
|
||||||
|
#define FS_OFFSET_1600_EXFAT_UNLOCK_MUTEX 0x186460
|
||||||
|
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x18CE90
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x18CEB0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SD_MUTEX 0x100D3F0
|
||||||
|
#define FS_OFFSET_1600_EXFAT_NAND_MUTEX 0x1008B58
|
||||||
|
#define FS_OFFSET_1600_EXFAT_ACTIVE_PARTITION 0x1008B98
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SDMMC_DAS_HANDLE 0xFE98B0
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1600_EXFAT_SD_DAS_INIT 0x258D4
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1600_EXFAT_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00063B48, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00070D6C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007790C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008A754, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1600_EXFAT_H__
|
||||||
59
emummc/source/FS/offsets/1603.h
vendored
Normal file
59
emummc/source/FS/offsets/1603.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_1603_H__
|
||||||
|
#define __FS_1603_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1603_SDMMC_ACCESSOR_GC 0x1862F0
|
||||||
|
#define FS_OFFSET_1603_SDMMC_ACCESSOR_SD 0x187F70
|
||||||
|
#define FS_OFFSET_1603_SDMMC_ACCESSOR_NAND 0x1867B0
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1603_SDMMC_WRAPPER_READ 0x182240
|
||||||
|
#define FS_OFFSET_1603_SDMMC_WRAPPER_WRITE 0x1822A0
|
||||||
|
#define FS_OFFSET_1603_RTLD 0x269B0
|
||||||
|
#define FS_OFFSET_1603_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1603_CLKRST_SET_MIN_V_CLK_RATE 0x1A2D80
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1603_LOCK_MUTEX 0x17B780
|
||||||
|
#define FS_OFFSET_1603_UNLOCK_MUTEX 0x17B7D0
|
||||||
|
|
||||||
|
#define FS_OFFSET_1603_SDMMC_WRAPPER_CONTROLLER_OPEN 0x182200
|
||||||
|
#define FS_OFFSET_1603_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x182220
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1603_SD_MUTEX 0xFFB3F0
|
||||||
|
#define FS_OFFSET_1603_NAND_MUTEX 0xFF6B58
|
||||||
|
#define FS_OFFSET_1603_ACTIVE_PARTITION 0xFF6B98
|
||||||
|
#define FS_OFFSET_1603_SDMMC_DAS_HANDLE 0xFDC8B0
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1603_SD_DAS_INIT 0x258D4
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1603_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00063B98, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00070DBC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007795C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008A7A4, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1603_H__
|
||||||
59
emummc/source/FS/offsets/1603_exfat.h
vendored
Normal file
59
emummc/source/FS/offsets/1603_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_1603_EXFAT_H__
|
||||||
|
#define __FS_1603_EXFAT_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_GC 0x190FD0
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_SD 0x192C50
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_ACCESSOR_NAND 0x191490
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_READ 0x18CF20
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_WRITE 0x18CF80
|
||||||
|
#define FS_OFFSET_1603_EXFAT_RTLD 0x269B0
|
||||||
|
#define FS_OFFSET_1603_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1603_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1ADA60
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1603_EXFAT_LOCK_MUTEX 0x186460
|
||||||
|
#define FS_OFFSET_1603_EXFAT_UNLOCK_MUTEX 0x1864B0
|
||||||
|
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x18CEE0
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x18CF00
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SD_MUTEX 0x100D3F0
|
||||||
|
#define FS_OFFSET_1603_EXFAT_NAND_MUTEX 0x1008B58
|
||||||
|
#define FS_OFFSET_1603_EXFAT_ACTIVE_PARTITION 0x1008B98
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SDMMC_DAS_HANDLE 0xFE98B0
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1603_EXFAT_SD_DAS_INIT 0x258D4
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1603_EXFAT_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00063B98, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00070DBC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007795C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0008A7A4, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1603_EXFAT_H__
|
||||||
@@ -85,10 +85,10 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
/* We can get away with only including latest because exosphere supports newer-than-expected master key in engine. */
|
/* 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. */
|
/* TODO: Update on next change of keys. */
|
||||||
/* Mariko Development Master Kek Source. */
|
/* Mariko Development Master Kek Source. */
|
||||||
.byte 0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7
|
.byte 0x3A, 0x9C, 0xF0, 0x39, 0x70, 0x23, 0xF6, 0xAF, 0x71, 0x44, 0x60, 0xF4, 0x6D, 0xED, 0xA1, 0xD6
|
||||||
|
|
||||||
/* Mariko Production Master Kek Source. */
|
/* Mariko Production Master Kek Source. */
|
||||||
.byte 0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D
|
.byte 0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9
|
||||||
|
|
||||||
/* Development Master Key Vectors. */
|
/* 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. */
|
.byte 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE /* Zeroes encrypted with Master Key 00. */
|
||||||
@@ -106,6 +106,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
.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 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 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. */
|
.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. */
|
||||||
|
.byte 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 /* Master key 0E encrypted with Master key 0F. */
|
||||||
|
|
||||||
/* Production Master Key Vectors. */
|
/* 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. */
|
.byte 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D /* Zeroes encrypted with Master Key 00. */
|
||||||
@@ -123,6 +124,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
.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 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 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. */
|
.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. */
|
||||||
|
.byte 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 /* Master key 0E encrypted with Master key 0F. */
|
||||||
|
|
||||||
/* Device Master Key Source Sources. */
|
/* 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. */
|
.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. */
|
||||||
@@ -137,6 +139,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
.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 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 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. */
|
.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. */
|
||||||
|
.byte 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C /* 16.0.0 Device Master Key Source Source. */
|
||||||
|
|
||||||
/* Development Device Master Kek Sources. */
|
/* 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. */
|
.byte 0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34 /* 4.0.0 Device Master Kek Source. */
|
||||||
@@ -151,6 +154,7 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
.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 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 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. */
|
.byte 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E /* 15.0.0 Device Master Kek Source. */
|
||||||
|
.byte 0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F /* 16.0.0 Device Master Kek Source. */
|
||||||
|
|
||||||
/* Production Device Master Kek Sources. */
|
/* 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. */
|
.byte 0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D /* 4.0.0 Device Master Kek Source. */
|
||||||
@@ -165,3 +169,4 @@ _ZN3ams6secmon4boot15VolatileKeyDataE:
|
|||||||
.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 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 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. */
|
.byte 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 /* 15.0.0 Device Master Kek Source. */
|
||||||
|
.byte 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F /* 16.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. */
|
/* Check that the key generation is one that we can use. */
|
||||||
static_assert(pkg1::KeyGeneration_Count == 15);
|
static_assert(pkg1::KeyGeneration_Count == 16);
|
||||||
if (key_generation >= pkg1::KeyGeneration_Count) {
|
if (key_generation >= pkg1::KeyGeneration_Count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,17 +23,17 @@ namespace ams::nxboot {
|
|||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSource[se::AesBlockSize] = {
|
||||||
/* TODO: Update on next change of keys. */
|
/* TODO: Update on next change of keys. */
|
||||||
0xEC, 0x61, 0xBC, 0x82, 0x1E, 0x0F, 0x5A, 0xC3, 0x2B, 0x64, 0x3F, 0x9D, 0xD6, 0x19, 0x22, 0x2D
|
0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 MarikoMasterKekSourceDev[se::AesBlockSize] = {
|
||||||
/* TODO: Update on next change of keys. */
|
/* TODO: Update on next change of keys. */
|
||||||
0x18, 0xA5, 0x6F, 0xEF, 0x72, 0x11, 0x62, 0xC5, 0x1A, 0x14, 0xF1, 0x8C, 0x21, 0x83, 0x27, 0xB7
|
0x3A, 0x9C, 0xF0, 0x39, 0x70, 0x23, 0xF6, 0xAF, 0x71, 0x44, 0x60, 0xF4, 0x6D, 0xED, 0xA1, 0xD6
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 EristaMasterKekSource[se::AesBlockSize] = {
|
||||||
/* TODO: Update on next change of keys. */
|
/* TODO: Update on next change of keys. */
|
||||||
0x6E, 0x77, 0x86, 0xAC, 0x83, 0x0A, 0x8D, 0x3E, 0x7D, 0xB7, 0x66, 0xA0, 0x22, 0xB7, 0x6E, 0x67
|
0x99, 0x22, 0x09, 0x57, 0xA7, 0xF9, 0x5E, 0x94, 0xFE, 0x78, 0x7F, 0x41, 0xD6, 0xE7, 0x56, 0xE6
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 KeyblobKeySource[se::AesBlockSize] = {
|
||||||
@@ -69,6 +69,7 @@ namespace ams::nxboot {
|
|||||||
{ 0xE4, 0xF3, 0x45, 0x6F, 0x18, 0xA1, 0x89, 0xF8, 0xDA, 0x4C, 0x64, 0x75, 0x68, 0xE6, 0xBD, 0x4F }, /* 13.0.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. */
|
{ 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. */
|
{ 0x5E, 0xC9, 0xC5, 0x0A, 0xD0, 0x5F, 0x8B, 0x7B, 0xA7, 0x39, 0xEA, 0xBC, 0x60, 0x0F, 0x74, 0xE6 }, /* 15.0.0 Device Master Key Source Source. */
|
||||||
|
{ 0xEA, 0x90, 0x6E, 0xA8, 0xAE, 0x92, 0x99, 0x64, 0x36, 0xC1, 0xF3, 0x1C, 0xC6, 0x32, 0x83, 0x8C }, /* 16.0.0 Device Master Key Source Source. */
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||||
@@ -84,6 +85,7 @@ namespace ams::nxboot {
|
|||||||
{ 0x77, 0x52, 0x92, 0xF0, 0xAA, 0xE3, 0xFB, 0xE0, 0x60, 0x16, 0xB3, 0x78, 0x68, 0x53, 0xF7, 0xA8 }, /* 13.0.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. */
|
{ 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. */
|
{ 0x7C, 0x30, 0xED, 0x8B, 0x39, 0x25, 0x2C, 0x08, 0x8F, 0x48, 0xDC, 0x28, 0xE6, 0x1A, 0x6B, 0x49 }, /* 15.0.0 Device Master Kek Source. */
|
||||||
|
{ 0xF0, 0xF3, 0xFF, 0x52, 0x75, 0x2F, 0xBA, 0x4D, 0x09, 0x72, 0x30, 0x89, 0xA9, 0xDF, 0xFE, 0x1F }, /* 16.0.0 Device Master Kek Source. */
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
|
||||||
@@ -99,6 +101,7 @@ namespace ams::nxboot {
|
|||||||
{ 0x20, 0x20, 0xAA, 0xFB, 0x89, 0xC2, 0xF0, 0x70, 0xB5, 0xE0, 0xA3, 0x11, 0x8A, 0x29, 0x8D, 0x0F }, /* 13.0.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. */
|
{ 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. */
|
{ 0xAE, 0x05, 0x48, 0x65, 0xAB, 0x17, 0x9D, 0x3D, 0x51, 0xB7, 0x56, 0xBD, 0x9B, 0x0B, 0x5B, 0x6E }, /* 15.0.0 Device Master Kek Source. */
|
||||||
|
{ 0xFF, 0xF6, 0x4B, 0x0F, 0xFF, 0x0D, 0xC0, 0x4F, 0x56, 0x8A, 0x40, 0x74, 0x67, 0xC5, 0xFE, 0x9F }, /* 16.0.0 Device Master Kek Source. */
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySources[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
||||||
@@ -117,6 +120,7 @@ namespace ams::nxboot {
|
|||||||
{ 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 }, /* Master key 0B encrypted with Master key 0C. */
|
{ 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. */
|
{ 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. */
|
{ 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 }, /* Master key 0D encrypted with Master key 0E. */
|
||||||
|
{ 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 }, /* Master key 0E encrypted with Master key 0F. */
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
alignas(se::AesBlockSize) constexpr inline const u8 MasterKeySourcesDev[pkg1::KeyGeneration_Count][se::AesBlockSize] = {
|
||||||
@@ -135,6 +139,7 @@ namespace ams::nxboot {
|
|||||||
{ 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 }, /* Master key 0B encrypted with Master key 0C. */
|
{ 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. */
|
{ 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. */
|
{ 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D }, /* Master key 0D encrypted with Master key 0E. */
|
||||||
|
{ 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 }, /* Master key 0E encrypted with Master key 0F. */
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {};
|
alignas(se::AesBlockSize) constinit u8 MasterKeys[pkg1::OldMasterKeyCount][se::AesBlockSize] = {};
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ namespace ams::nxboot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the key generation is one that we can use. */
|
/* Check that the key generation is one that we can use. */
|
||||||
static_assert(pkg1::KeyGeneration_Count == 15);
|
static_assert(pkg1::KeyGeneration_Count == 16);
|
||||||
if (key_generation >= pkg1::KeyGeneration_Count) {
|
if (key_generation >= pkg1::KeyGeneration_Count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,6 +255,8 @@ namespace ams::nxboot {
|
|||||||
return ams::TargetFirmware_14_0_0;
|
return ams::TargetFirmware_14_0_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20220801", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20220801", 8) == 0) {
|
||||||
return ams::TargetFirmware_15_0_0;
|
return ams::TargetFirmware_15_0_0;
|
||||||
|
} else if (std::memcmp(package1 + 0x10, "20230111", 8) == 0) {
|
||||||
|
return ams::TargetFirmware_16_0_0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -159,6 +159,12 @@ namespace ams::nxboot {
|
|||||||
FsVersion_15_0_0,
|
FsVersion_15_0_0,
|
||||||
FsVersion_15_0_0_Exfat,
|
FsVersion_15_0_0_Exfat,
|
||||||
|
|
||||||
|
FsVersion_16_0_0,
|
||||||
|
FsVersion_16_0_0_Exfat,
|
||||||
|
|
||||||
|
FsVersion_16_0_3,
|
||||||
|
FsVersion_16_0_3_Exfat,
|
||||||
|
|
||||||
FsVersion_Count,
|
FsVersion_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -231,9 +237,14 @@ namespace ams::nxboot {
|
|||||||
{ 0x88, 0x7A, 0xC1, 0x50, 0x80, 0x6C, 0x75, 0xCC }, /* FsVersion_14_0_0 */
|
{ 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 */
|
{ 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 */
|
{ 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 */
|
{ 0x34, 0xC0, 0xD9, 0xED, 0x6A, 0xD1, 0x87, 0x3D }, /* FsVersion_15_0_0_Exfat */
|
||||||
|
|
||||||
|
{ 0x56, 0xE8, 0x56, 0x56, 0x6C, 0x38, 0xD8, 0xBE }, /* FsVersion_16_0_0 */
|
||||||
|
{ 0xCF, 0xAB, 0x45, 0x0C, 0x2C, 0x53, 0x9D, 0xA9 }, /* FsVersion_16_0_0_Exfat */
|
||||||
|
|
||||||
|
{ 0x39, 0xEE, 0x1F, 0x1E, 0x0E, 0xA7, 0x32, 0x5D }, /* FsVersion_16_0_3 */
|
||||||
|
{ 0x62, 0xC6, 0x5E, 0xFD, 0x9A, 0xBF, 0x7C, 0x43 }, /* FsVersion_16_0_3_Exfat */
|
||||||
};
|
};
|
||||||
|
|
||||||
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
|
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
|
||||||
@@ -643,6 +654,22 @@ namespace ams::nxboot {
|
|||||||
AddPatch(fs_meta, 0x18F1E9, NogcPatch0, sizeof(NogcPatch0));
|
AddPatch(fs_meta, 0x18F1E9, NogcPatch0, sizeof(NogcPatch0));
|
||||||
AddPatch(fs_meta, 0x169D74, NogcPatch1, sizeof(NogcPatch1));
|
AddPatch(fs_meta, 0x169D74, NogcPatch1, sizeof(NogcPatch1));
|
||||||
break;
|
break;
|
||||||
|
case FsVersion_16_0_0:
|
||||||
|
AddPatch(fs_meta, 0x1866D9, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x160C70, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_16_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x1913B9, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x16B950, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_16_0_3:
|
||||||
|
AddPatch(fs_meta, 0x186729, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x160CC0, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_16_0_3_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x191409, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x16B9A0, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||||
branch = master
|
branch = master
|
||||||
commit = b7711b8fbcec5013e1738218267d69b2cb44f85e
|
commit = cd0fc2c1d5728ec45414aaaa6efa28c269695992
|
||||||
parent = 590f22933db38f089ab2224f7fd86658a9533e8d
|
parent = 8ec7c096d04e6f9586be2cb785840cd482d4b900
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.4.1
|
cmdver = 0.4.1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_WINDOWS
|
export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_WINDOWS
|
||||||
export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer
|
export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer -fno-data-sections
|
||||||
export ATMOSPHERE_CFLAGS +=
|
export ATMOSPHERE_CFLAGS +=
|
||||||
export ATMOSPHERE_CXXFLAGS +=
|
export ATMOSPHERE_CXXFLAGS +=
|
||||||
export ATMOSPHERE_ASFLAGS +=
|
export ATMOSPHERE_ASFLAGS +=
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
|
|||||||
-Wl,--wrap,exit
|
-Wl,--wrap,exit
|
||||||
else ifeq ($(ATMOSPHERE_BOARD),generic_windows)
|
else ifeq ($(ATMOSPHERE_BOARD),generic_windows)
|
||||||
export CXXREQUIRED :=
|
export CXXREQUIRED :=
|
||||||
export CXXWRAPS := -Wl,--wrap,__p__acmdln
|
export CXXWRAPS := -Wl,--wrap,__p__acmdln -Wl,--wrap,_set_invalid_parameter_handler
|
||||||
else
|
else
|
||||||
export CXXREQUIRED :=
|
export CXXREQUIRED :=
|
||||||
export CXXWRAPS :=
|
export CXXWRAPS :=
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace ams::pkg1 {
|
|||||||
KeyGeneration_13_0_0 = 0x0C,
|
KeyGeneration_13_0_0 = 0x0C,
|
||||||
KeyGeneration_14_0_0 = 0x0D,
|
KeyGeneration_14_0_0 = 0x0D,
|
||||||
KeyGeneration_15_0_0 = 0x0E,
|
KeyGeneration_15_0_0 = 0x0E,
|
||||||
|
KeyGeneration_16_0_0 = 0x0F,
|
||||||
|
|
||||||
KeyGeneration_Count,
|
KeyGeneration_Count,
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ namespace ams::pkg2 {
|
|||||||
|
|
||||||
constexpr inline int PayloadCount = 3;
|
constexpr inline int PayloadCount = 3;
|
||||||
|
|
||||||
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x16 in Nintendo's code. */
|
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x17 in Nintendo's code. */
|
||||||
constexpr inline int CurrentBootloaderVersion = 0x12;
|
constexpr inline int CurrentBootloaderVersion = 0x13;
|
||||||
|
|
||||||
struct Package2Meta {
|
struct Package2Meta {
|
||||||
using Magic = util::FourCC<'P','K','2','1'>;
|
using Magic = util::FourCC<'P','K','2','1'>;
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ namespace ams::fuse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
||||||
|
TargetFirmware_16_0_0,
|
||||||
TargetFirmware_15_0_0,
|
TargetFirmware_15_0_0,
|
||||||
TargetFirmware_13_2_1,
|
TargetFirmware_13_2_1,
|
||||||
TargetFirmware_12_0_2,
|
TargetFirmware_12_0_2,
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ namespace ams::kern::init {
|
|||||||
u64 sp;
|
u64 sp;
|
||||||
u64 entrypoint;
|
u64 entrypoint;
|
||||||
u64 argument;
|
u64 argument;
|
||||||
u64 setup_function;
|
|
||||||
u64 exception_stack;
|
|
||||||
};
|
};
|
||||||
static_assert(alignof(KInitArguments) == util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE));
|
static_assert(alignof(KInitArguments) == util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE));
|
||||||
static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)));
|
static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)));
|
||||||
@@ -45,7 +43,5 @@ namespace ams::kern::init {
|
|||||||
static_assert(AMS_OFFSETOF(KInitArguments, sp) == INIT_ARGUMENTS_SP);
|
static_assert(AMS_OFFSETOF(KInitArguments, sp) == INIT_ARGUMENTS_SP);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
|
static_assert(AMS_OFFSETOF(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
|
static_assert(AMS_OFFSETOF(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, setup_function) == INIT_ARGUMENTS_SETUP_FUNCTION);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, exception_stack) == INIT_ARGUMENTS_EXCEPTION_STACK);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -23,17 +23,6 @@
|
|||||||
|
|
||||||
namespace ams::kern::arch::arm64::init {
|
namespace ams::kern::arch::arm64::init {
|
||||||
|
|
||||||
inline void ClearPhysicalMemory(KPhysicalAddress address, size_t size) {
|
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, sizeof(u64)));
|
|
||||||
|
|
||||||
/* This Physical Address -> void * conversion is valid, because this is init page table code. */
|
|
||||||
/* The MMU is necessarily not yet turned on, if we are creating an initial page table. */
|
|
||||||
volatile u64 *ptr = reinterpret_cast<volatile u64 *>(GetInteger(address));
|
|
||||||
for (size_t i = 0; i < size / sizeof(u64); ++i) {
|
|
||||||
ptr[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTE: Nintendo uses virtual functions, rather than a concept + template. */
|
/* NOTE: Nintendo uses virtual functions, rather than a concept + template. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept IsInitialPageAllocator = requires (T &t, KPhysicalAddress phys_addr, size_t size) {
|
concept IsInitialPageAllocator = requires (T &t, KPhysicalAddress phys_addr, size_t size) {
|
||||||
@@ -41,25 +30,23 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
{ t.Free(phys_addr, size) } -> std::same_as<void>;
|
{ t.Free(phys_addr, size) } -> std::same_as<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<IsInitialPageAllocator _PageAllocator>
|
class KInitialPageTable {
|
||||||
class KInitialPageTableTemplate {
|
|
||||||
public:
|
|
||||||
using PageAllocator = _PageAllocator;
|
|
||||||
private:
|
private:
|
||||||
KPhysicalAddress m_l1_tables[2];
|
KPhysicalAddress m_l1_tables[2];
|
||||||
u32 m_num_entries[2];
|
u32 m_num_entries[2];
|
||||||
public:
|
public:
|
||||||
KInitialPageTableTemplate(KVirtualAddress start_address, KVirtualAddress end_address, PageAllocator &allocator) {
|
template<IsInitialPageAllocator PageAllocator>
|
||||||
|
KInitialPageTable(KVirtualAddress start_address, KVirtualAddress end_address, PageAllocator &allocator) {
|
||||||
/* Set tables. */
|
/* Set tables. */
|
||||||
m_l1_tables[0] = AllocateNewPageTable(allocator);
|
m_l1_tables[0] = AllocateNewPageTable(allocator, 0);
|
||||||
m_l1_tables[1] = AllocateNewPageTable(allocator);
|
m_l1_tables[1] = AllocateNewPageTable(allocator, 0);
|
||||||
|
|
||||||
/* Set counts. */
|
/* Set counts. */
|
||||||
m_num_entries[0] = MaxPageTableEntries;
|
m_num_entries[0] = MaxPageTableEntries;
|
||||||
m_num_entries[1] = ((end_address / L1BlockSize) & (MaxPageTableEntries - 1)) - ((start_address / L1BlockSize) & (MaxPageTableEntries - 1)) + 1;
|
m_num_entries[1] = ((end_address / L1BlockSize) & (MaxPageTableEntries - 1)) - ((start_address / L1BlockSize) & (MaxPageTableEntries - 1)) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
KInitialPageTableTemplate() {
|
KInitialPageTable() {
|
||||||
/* Set tables. */
|
/* Set tables. */
|
||||||
m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize);
|
m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize);
|
||||||
m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize);
|
m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize);
|
||||||
@@ -82,30 +69,35 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
return GetInteger(m_l1_tables[1]);
|
return GetInteger(m_l1_tables[1]);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KVirtualAddress address) const {
|
constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KVirtualAddress address, u64 phys_to_virt_offset = 0) const {
|
||||||
const size_t index = (GetInteger(address) >> (BITSIZEOF(address) - 1)) & 1;
|
const size_t index = (GetInteger(address) >> (BITSIZEOF(address) - 1)) & 1;
|
||||||
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[index]));
|
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[index]) + phys_to_virt_offset);
|
||||||
return l1_table + ((GetInteger(address) / L1BlockSize) & (m_num_entries[index] - 1));
|
return l1_table + ((GetInteger(address) / L1BlockSize) & (m_num_entries[index] - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KVirtualAddress address) {
|
static constexpr ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KVirtualAddress address, u64 phys_to_virt_offset = 0) {
|
||||||
L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()));
|
L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()) + phys_to_virt_offset);
|
||||||
return l2_table + ((GetInteger(address) / L2BlockSize) & (MaxPageTableEntries - 1));
|
return l2_table + ((GetInteger(address) / L2BlockSize) & (MaxPageTableEntries - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KVirtualAddress address) {
|
static constexpr ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KVirtualAddress address, u64 phys_to_virt_offset = 0) {
|
||||||
L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()));
|
L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()) + phys_to_virt_offset);
|
||||||
return l3_table + ((GetInteger(address) / L3BlockSize) & (MaxPageTableEntries - 1));
|
return l3_table + ((GetInteger(address) / L3BlockSize) & (MaxPageTableEntries - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(PageAllocator &allocator) {
|
template<IsInitialPageAllocator PageAllocator>
|
||||||
|
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(PageAllocator &allocator, u64 phys_to_virt_offset) {
|
||||||
auto address = allocator.Allocate(PageSize);
|
auto address = allocator.Allocate(PageSize);
|
||||||
ClearNewPageTable(address);
|
ClearNewPageTable(address, phys_to_virt_offset);
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address) {
|
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address, u64 phys_to_virt_offset) {
|
||||||
ClearPhysicalMemory(address, PageSize);
|
/* Convert to a deferenceable address, and clear. */
|
||||||
|
volatile u64 *ptr = reinterpret_cast<volatile u64 *>(GetInteger(address) + phys_to_virt_offset);
|
||||||
|
for (size_t i = 0; i < PageSize / sizeof(u64); ++i) {
|
||||||
|
ptr[i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
static consteval size_t GetMaximumOverheadSize(size_t size) {
|
static consteval size_t GetMaximumOverheadSize(size_t size) {
|
||||||
@@ -327,7 +319,8 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, PageAllocator &allocator) {
|
template<IsInitialPageAllocator PageAllocator>
|
||||||
|
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, PageAllocator &allocator, u64 phys_to_virt_offset) {
|
||||||
/* Ensure that addresses and sizes are page aligned. */
|
/* Ensure that addresses and sizes are page aligned. */
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize));
|
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize));
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize));
|
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize));
|
||||||
@@ -335,7 +328,7 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
/* Iteratively map pages until the requested region is mapped. */
|
/* Iteratively map pages until the requested region is mapped. */
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr, phys_to_virt_offset);
|
||||||
|
|
||||||
/* Can we make an L1 block? */
|
/* Can we make an L1 block? */
|
||||||
if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && size >= L1BlockSize) {
|
if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && size >= L1BlockSize) {
|
||||||
@@ -349,12 +342,12 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
/* If we don't already have an L2 table, we need to make a new one. */
|
/* If we don't already have an L2 table, we need to make a new one. */
|
||||||
if (!l1_entry->IsTable()) {
|
if (!l1_entry->IsTable()) {
|
||||||
KPhysicalAddress new_table = AllocateNewPageTable(allocator);
|
KPhysicalAddress new_table = AllocateNewPageTable(allocator, phys_to_virt_offset);
|
||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
||||||
}
|
}
|
||||||
|
|
||||||
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
|
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr, phys_to_virt_offset);
|
||||||
|
|
||||||
/* Can we make a contiguous L2 block? */
|
/* Can we make a contiguous L2 block? */
|
||||||
if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && size >= L2ContiguousBlockSize) {
|
if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && size >= L2ContiguousBlockSize) {
|
||||||
@@ -380,12 +373,12 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
/* If we don't already have an L3 table, we need to make a new one. */
|
/* If we don't already have an L3 table, we need to make a new one. */
|
||||||
if (!l2_entry->IsTable()) {
|
if (!l2_entry->IsTable()) {
|
||||||
KPhysicalAddress new_table = AllocateNewPageTable(allocator);
|
KPhysicalAddress new_table = AllocateNewPageTable(allocator, phys_to_virt_offset);
|
||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
||||||
}
|
}
|
||||||
|
|
||||||
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
|
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr, phys_to_virt_offset);
|
||||||
|
|
||||||
/* Can we make a contiguous L3 block? */
|
/* Can we make a contiguous L3 block? */
|
||||||
if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && size >= L3ContiguousBlockSize) {
|
if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && size >= L3ContiguousBlockSize) {
|
||||||
@@ -410,6 +403,98 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UnmapTtbr0Entries(u64 phys_to_virt_offset) {
|
||||||
|
/* Ensure data consistency before we unmap. */
|
||||||
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
|
|
||||||
|
/* Define helper, as we only want to clear non-nGnRE pages. */
|
||||||
|
constexpr auto ShouldUnmap = [](const PageTableEntry *entry) ALWAYS_INLINE_LAMBDA -> bool {
|
||||||
|
return entry->GetPageAttribute() != PageTableEntry::PageAttribute_Device_nGnRE;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Iterate all L1 entries. */
|
||||||
|
L1PageTableEntry * const l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(m_l1_tables[0]) + phys_to_virt_offset);
|
||||||
|
for (size_t l1_index = 0; l1_index < m_num_entries[0]; l1_index++) {
|
||||||
|
/* Get L1 entry. */
|
||||||
|
L1PageTableEntry * const l1_entry = l1_table + l1_index;
|
||||||
|
if (l1_entry->IsBlock()) {
|
||||||
|
/* Unmap the L1 entry, if we should. */
|
||||||
|
if (ShouldUnmap(l1_entry)) {
|
||||||
|
*static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry;
|
||||||
|
}
|
||||||
|
} else if (l1_entry->IsTable()) {
|
||||||
|
/* Get the L2 table. */
|
||||||
|
L2PageTableEntry * const l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(l1_entry->GetTable()) + phys_to_virt_offset);
|
||||||
|
|
||||||
|
/* Unmap all L2 entries, as relevant. */
|
||||||
|
size_t remaining_l2_entries = 0;
|
||||||
|
for (size_t l2_index = 0; l2_index < MaxPageTableEntries; ++l2_index) {
|
||||||
|
/* Get L2 entry. */
|
||||||
|
L2PageTableEntry * const l2_entry = l2_table + l2_index;
|
||||||
|
if (l2_entry->IsBlock()) {
|
||||||
|
const size_t num_to_clear = (l2_entry->IsContiguous() ? L2ContiguousBlockSize : L2BlockSize) / L2BlockSize;
|
||||||
|
|
||||||
|
if (ShouldUnmap(l2_entry)) {
|
||||||
|
for (size_t i = 0; i < num_to_clear; ++i) {
|
||||||
|
static_cast<PageTableEntry *>(l2_entry)[i] = InvalidPageTableEntry;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remaining_l2_entries += num_to_clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
l2_index = l2_index + num_to_clear - 1;
|
||||||
|
} else if (l2_entry->IsTable()) {
|
||||||
|
/* Get the L3 table. */
|
||||||
|
L3PageTableEntry * const l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(l2_entry->GetTable()) + phys_to_virt_offset);
|
||||||
|
|
||||||
|
/* Unmap all L3 entries, as relevant. */
|
||||||
|
size_t remaining_l3_entries = 0;
|
||||||
|
for (size_t l3_index = 0; l3_index < MaxPageTableEntries; ++l3_index) {
|
||||||
|
/* Get L3 entry. */
|
||||||
|
if (L3PageTableEntry * const l3_entry = l3_table + l3_index; l3_entry->IsBlock()) {
|
||||||
|
const size_t num_to_clear = (l3_entry->IsContiguous() ? L3ContiguousBlockSize : L3BlockSize) / L3BlockSize;
|
||||||
|
|
||||||
|
if (ShouldUnmap(l3_entry)) {
|
||||||
|
for (size_t i = 0; i < num_to_clear; ++i) {
|
||||||
|
static_cast<PageTableEntry *>(l3_entry)[i] = InvalidPageTableEntry;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remaining_l3_entries += num_to_clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
l3_index = l3_index + num_to_clear - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we unmapped all L3 entries, clear the L2 entry. */
|
||||||
|
if (remaining_l3_entries == 0) {
|
||||||
|
*static_cast<PageTableEntry *>(l2_entry) = InvalidPageTableEntry;
|
||||||
|
|
||||||
|
/* Invalidate the entire tlb. */
|
||||||
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
|
cpu::InvalidateEntireTlb();
|
||||||
|
} else {
|
||||||
|
remaining_l2_entries++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we unmapped all L2 entries, clear the L1 entry. */
|
||||||
|
if (remaining_l2_entries == 0) {
|
||||||
|
*static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry;
|
||||||
|
|
||||||
|
/* Invalidate the entire tlb. */
|
||||||
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
|
cpu::InvalidateEntireTlb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Invalidate the entire tlb. */
|
||||||
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
|
cpu::InvalidateEntireTlb();
|
||||||
|
}
|
||||||
|
|
||||||
KPhysicalAddress GetPhysicalAddress(KVirtualAddress virt_addr) const {
|
KPhysicalAddress GetPhysicalAddress(KVirtualAddress virt_addr) const {
|
||||||
/* Get the L1 entry. */
|
/* Get the L1 entry. */
|
||||||
const L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
const L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||||
@@ -861,6 +946,4 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
};
|
};
|
||||||
static_assert(IsInitialPageAllocator<KInitialPageAllocator>);
|
static_assert(IsInitialPageAllocator<KInitialPageAllocator>);
|
||||||
|
|
||||||
using KInitialPageTable = KInitialPageTableTemplate<KInitialPageAllocator>;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#define THREAD_KERNEL_STACK_TOP 0x280
|
#define THREAD_KERNEL_STACK_TOP 0x280
|
||||||
|
|
||||||
/* ams::kern::KThread::StackParameters, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */
|
/* ams::kern::KThread::StackParameters, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */
|
||||||
#define THREAD_STACK_PARAMETERS_SIZE 0x130
|
#define THREAD_STACK_PARAMETERS_SIZE 0x140
|
||||||
#define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00
|
#define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00
|
||||||
#define THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS 0x18
|
#define THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS 0x18
|
||||||
#define THREAD_STACK_PARAMETERS_CUR_THREAD 0x20
|
#define THREAD_STACK_PARAMETERS_CUR_THREAD 0x20
|
||||||
@@ -34,7 +34,8 @@
|
|||||||
#define THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS 0x2D
|
#define THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS 0x2D
|
||||||
#define THREAD_STACK_PARAMETERS_IS_PINNED 0x2E
|
#define THREAD_STACK_PARAMETERS_IS_PINNED 0x2E
|
||||||
#define THREAD_STACK_PARAMETERS_RESERVED_2F 0x2F
|
#define THREAD_STACK_PARAMETERS_RESERVED_2F 0x2F
|
||||||
#define THREAD_STACK_PARAMETERS_THREAD_CONTEXT 0x30
|
#define THREAD_STACK_PARAMETERS_RESERVED_30 0x30
|
||||||
|
#define THREAD_STACK_PARAMETERS_THREAD_CONTEXT 0x40
|
||||||
|
|
||||||
#define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_CALLING_SVC (0)
|
#define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_CALLING_SVC (0)
|
||||||
#define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_EXCEPTION_HANDLER (1)
|
#define THREAD_EXCEPTION_FLAG_BIT_INDEX_IS_IN_EXCEPTION_HANDLER (1)
|
||||||
@@ -245,7 +246,7 @@
|
|||||||
#define THREAD_LOCAL_REGION_SIZE 0x200
|
#define THREAD_LOCAL_REGION_SIZE 0x200
|
||||||
|
|
||||||
/* ams::kern::init::KInitArguments, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_arguments.hpp */
|
/* ams::kern::init::KInitArguments, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_arguments.hpp */
|
||||||
#define INIT_ARGUMENTS_SIZE 0x60
|
#define INIT_ARGUMENTS_SIZE 0x50
|
||||||
#define INIT_ARGUMENTS_TTBR0 0x00
|
#define INIT_ARGUMENTS_TTBR0 0x00
|
||||||
#define INIT_ARGUMENTS_TTBR1 0x08
|
#define INIT_ARGUMENTS_TTBR1 0x08
|
||||||
#define INIT_ARGUMENTS_TCR 0x10
|
#define INIT_ARGUMENTS_TCR 0x10
|
||||||
@@ -256,14 +257,12 @@
|
|||||||
#define INIT_ARGUMENTS_SP 0x38
|
#define INIT_ARGUMENTS_SP 0x38
|
||||||
#define INIT_ARGUMENTS_ENTRYPOINT 0x40
|
#define INIT_ARGUMENTS_ENTRYPOINT 0x40
|
||||||
#define INIT_ARGUMENTS_ARGUMENT 0x48
|
#define INIT_ARGUMENTS_ARGUMENT 0x48
|
||||||
#define INIT_ARGUMENTS_SETUP_FUNCTION 0x50
|
|
||||||
#define INIT_ARGUMENTS_EXCEPTION_STACK 0x58
|
|
||||||
|
|
||||||
/* ams::kern::KScheduler (::SchedulingState), https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp */
|
/* ams::kern::KScheduler (::SchedulingState), https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp */
|
||||||
/* NOTE: Due to constraints on ldarb relative offsets, KSCHEDULER_NEEDS_SCHEDULING cannot trivially be changed, and will require assembly edits. */
|
/* NOTE: Due to constraints on ldarb relative offsets, KSCHEDULER_NEEDS_SCHEDULING cannot trivially be changed, and will require assembly edits. */
|
||||||
#define KSCHEDULER_NEEDS_SCHEDULING 0x00
|
#define KSCHEDULER_NEEDS_SCHEDULING 0x00
|
||||||
#define KSCHEDULER_INTERRUPT_TASK_RUNNABLE 0x01
|
#define KSCHEDULER_INTERRUPT_TASK_RUNNABLE 0x01
|
||||||
#define KSCHEDULER_HIGHEST_PRIORITY_THREAD 0x10
|
#define KSCHEDULER_HIGHEST_PRIORITY_THREAD 0x18
|
||||||
#define KSCHEDULER_IDLE_THREAD_STACK 0x18
|
#define KSCHEDULER_IDLE_THREAD_STACK 0x20
|
||||||
#define KSCHEDULER_PREVIOUS_THREAD 0x20
|
#define KSCHEDULER_PREVIOUS_THREAD 0x28
|
||||||
#define KSCHEDULER_INTERRUPT_TASK_MANAGER 0x28
|
#define KSCHEDULER_INTERRUPT_TASK_MANAGER 0x30
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
#error "Unknown Board for cpu::NumCores"
|
#error "Unknown Board for cpu::NumCores"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
constexpr inline u32 El0Aarch64PsrMask = 0xF0000000;
|
||||||
|
constexpr inline u32 El0Aarch32PsrMask = 0xFE0FFE20;
|
||||||
|
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
NOINLINE void InitializeInterruptThreads(s32 core_id);
|
NOINLINE void InitializeInterruptThreads(s32 core_id);
|
||||||
|
|
||||||
@@ -186,6 +189,14 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
return (par >> (BITSIZEOF(par) - BITSIZEOF(u8))) == 0xFF;
|
return (par >> (BITSIZEOF(par) - BITSIZEOF(u8))) == 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void StoreDataCacheForInitArguments(const void *addr, size_t size) {
|
||||||
|
const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize);
|
||||||
|
for (size_t stored = 0; stored < size; stored += cpu::DataCacheLineSize) {
|
||||||
|
__asm__ __volatile__("dc cvac, %[cur]" :: [cur]"r"(start + stored) : "memory");
|
||||||
|
}
|
||||||
|
DataSynchronizationBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
/* Synchronization helpers. */
|
/* Synchronization helpers. */
|
||||||
NOINLINE void SynchronizeAllCores();
|
NOINLINE void SynchronizeAllCores();
|
||||||
void SynchronizeCores(u64 core_mask);
|
void SynchronizeCores(u64 core_mask);
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
ALWAYS_INLINE Result SeparatePagesImpl(KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll);
|
ALWAYS_INLINE Result SeparatePagesImpl(KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll);
|
||||||
Result SeparatePages(KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll);
|
Result SeparatePages(KProcessAddress virt_addr, size_t block_size, PageLinkedList *page_list, bool reuse_ll);
|
||||||
|
|
||||||
Result ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, PageLinkedList *page_list, bool reuse_ll);
|
Result ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, bool flush_mapping, PageLinkedList *page_list, bool reuse_ll);
|
||||||
|
|
||||||
static ALWAYS_INLINE void PteDataMemoryBarrier() {
|
static ALWAYS_INLINE void PteDataMemoryBarrier() {
|
||||||
cpu::DataMemoryBarrierInnerShareableStore();
|
cpu::DataMemoryBarrierInnerShareableStore();
|
||||||
|
|||||||
@@ -161,9 +161,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsGlobal() const { return this->GetBits(11, 1) == 0; }
|
constexpr ALWAYS_INLINE bool IsGlobal() const { return this->GetBits(11, 1) == 0; }
|
||||||
constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast<AccessFlag>(this->GetBits(10, 1)); }
|
constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast<AccessFlag>(this->SelectBits(10, 1)); }
|
||||||
constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast<Shareable>(this->GetBits(8, 2)); }
|
constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast<Shareable>(this->SelectBits(8, 2)); }
|
||||||
constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast<PageAttribute>(this->GetBits(2, 3)); }
|
constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast<PageAttribute>(this->SelectBits(2, 3)); }
|
||||||
|
constexpr ALWAYS_INLINE int GetAccessFlagInteger() const { return static_cast<int>(this->GetBits(10, 1)); }
|
||||||
|
constexpr ALWAYS_INLINE int GetShareableInteger() const { return static_cast<int>(this->GetBits(8, 2)); }
|
||||||
|
constexpr ALWAYS_INLINE int GetPageAttributeInteger() const { return static_cast<int>(this->GetBits(2, 3)); }
|
||||||
constexpr ALWAYS_INLINE bool IsReadOnly() const { return this->GetBits(7, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsReadOnly() const { return this->GetBits(7, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_RETURN(m_page_table.MapIoRegion(dst_address, phys_addr, size, mapping, perm));
|
R_RETURN(m_page_table.MapIoRegion(dst_address, phys_addr, size, mapping, perm));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size) {
|
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping) {
|
||||||
R_RETURN(m_page_table.UnmapIoRegion(dst_address, phys_addr, size));
|
R_RETURN(m_page_table.UnmapIoRegion(dst_address, phys_addr, size, mapping));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) {
|
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) {
|
||||||
|
|||||||
@@ -25,12 +25,15 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
static constexpr size_t SecureAppletMemorySize = 4_MB;
|
static constexpr size_t SecureAppletMemorySize = 4_MB;
|
||||||
public:
|
public:
|
||||||
class Init : public KSystemControlBase::Init {
|
class Init : public KSystemControlBase::Init {
|
||||||
|
private:
|
||||||
|
friend class KSystemControlBase::Init;
|
||||||
|
private:
|
||||||
|
static void CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
||||||
public:
|
public:
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
static size_t GetRealMemorySize();
|
static size_t GetRealMemorySize();
|
||||||
static size_t GetIntendedMemorySize();
|
static size_t GetIntendedMemorySize();
|
||||||
static bool ShouldIncreaseThreadResourceLimit();
|
static bool ShouldIncreaseThreadResourceLimit();
|
||||||
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
|
||||||
static size_t GetApplicationPoolSize();
|
static size_t GetApplicationPoolSize();
|
||||||
static size_t GetAppletPoolSize();
|
static size_t GetAppletPoolSize();
|
||||||
static size_t GetMinimumNonSecureSystemPoolSize();
|
static size_t GetMinimumNonSecureSystemPoolSize();
|
||||||
|
|||||||
@@ -26,6 +26,6 @@ namespace ams::kern::init {
|
|||||||
|
|
||||||
static_assert(util::IsPowerOfTwo(alignof(KInitArguments)) && util::IsPowerOfTwo(sizeof(KInitArguments)));
|
static_assert(util::IsPowerOfTwo(alignof(KInitArguments)) && util::IsPowerOfTwo(sizeof(KInitArguments)));
|
||||||
|
|
||||||
KPhysicalAddress GetInitArgumentsAddress(s32 core_id);
|
KInitArguments *GetInitArguments(s32 core_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,11 @@
|
|||||||
#define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP
|
#define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP
|
||||||
#define MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP
|
#define MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP
|
||||||
|
|
||||||
|
/* NOTE: In 16.0.0, Nintendo deleted the creation time field for KProcess, */
|
||||||
|
/* but this may be useful for some debugging applications, and so can be. */
|
||||||
|
/* re-enabled by toggling this define. */
|
||||||
|
//#define MESOSPHERE_ENABLE_PROCESS_CREATION_TIME
|
||||||
|
|
||||||
/* NOTE: This enables fast class token storage using a class member. */
|
/* NOTE: This enables fast class token storage using a class member. */
|
||||||
/* This saves a virtual call when doing KAutoObject->DynCast<>(), */
|
/* This saves a virtual call when doing KAutoObject->DynCast<>(), */
|
||||||
/* at the cost of storing class tokens inside the class object. */
|
/* at the cost of storing class tokens inside the class object. */
|
||||||
|
|||||||
@@ -40,12 +40,16 @@ namespace ams::kern {
|
|||||||
static uintptr_t GetAddressSpaceStart(size_t width, Type type);
|
static uintptr_t GetAddressSpaceStart(size_t width, Type type);
|
||||||
static size_t GetAddressSpaceSize(size_t width, Type type);
|
static size_t GetAddressSpaceSize(size_t width, Type type);
|
||||||
|
|
||||||
|
static void SetAddressSpaceSize(size_t width, Type type, size_t size);
|
||||||
|
|
||||||
constexpr KAddressSpaceInfo(size_t bw, size_t a, size_t s, Type t) : m_bit_width(bw), m_address(a), m_size(s), m_type(t) { /* ... */ }
|
constexpr KAddressSpaceInfo(size_t bw, size_t a, size_t s, Type t) : m_bit_width(bw), m_address(a), m_size(s), m_type(t) { /* ... */ }
|
||||||
|
|
||||||
constexpr size_t GetWidth() const { return m_bit_width; }
|
constexpr size_t GetWidth() const { return m_bit_width; }
|
||||||
constexpr size_t GetAddress() const { return m_address; }
|
constexpr size_t GetAddress() const { return m_address; }
|
||||||
constexpr size_t GetSize() const { return m_size; }
|
constexpr size_t GetSize() const { return m_size; }
|
||||||
constexpr Type GetType() const { return m_type; }
|
constexpr Type GetType() const { return m_type; }
|
||||||
|
|
||||||
|
constexpr void SetSize(size_t size) { m_size = size; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool Close() {
|
ALWAYS_INLINE bool Close() {
|
||||||
/* Atomically decrement the reference count, not allowing it to become negative. */
|
/* Atomically decrement the reference count, not allowing it to decrement past zero. */
|
||||||
u32 cur = m_value.Load<std::memory_order_relaxed>();
|
u32 cur = m_value.Load<std::memory_order_relaxed>();
|
||||||
do {
|
do {
|
||||||
MESOSPHERE_ABORT_UNLESS(cur > 0);
|
MESOSPHERE_ABORT_UNLESS(cur > 0);
|
||||||
@@ -257,7 +257,7 @@ namespace ams::kern {
|
|||||||
class KScopedAutoObject {
|
class KScopedAutoObject {
|
||||||
NON_COPYABLE(KScopedAutoObject);
|
NON_COPYABLE(KScopedAutoObject);
|
||||||
private:
|
private:
|
||||||
template<typename U>
|
template<typename U> requires std::derived_from<U, KAutoObject>
|
||||||
friend class KScopedAutoObject;
|
friend class KScopedAutoObject;
|
||||||
private:
|
private:
|
||||||
T *m_obj;
|
T *m_obj;
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace ams::kern {
|
|||||||
return m_process_holder.Get();
|
return m_process_holder.Get();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
void PushDebugEvent(ams::svc::DebugEvent event, uintptr_t param0 = 0, uintptr_t param1 = 0, uintptr_t param2 = 0, uintptr_t param3 = 0, uintptr_t param4 = 0);
|
void PushDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
|
||||||
void EnqueueDebugEventInfo(KEventInfo *info);
|
void EnqueueDebugEventInfo(KEventInfo *info);
|
||||||
|
|
||||||
template<typename T> requires (std::same_as<T, ams::svc::lp64::DebugEventInfo> || std::same_as<T, ams::svc::ilp32::DebugEventInfo>)
|
template<typename T> requires (std::same_as<T, ams::svc::lp64::DebugEventInfo> || std::same_as<T, ams::svc::ilp32::DebugEventInfo>)
|
||||||
@@ -85,13 +85,13 @@ namespace ams::kern {
|
|||||||
/* NOTE: This is public/virtual override in Nintendo's kernel. */
|
/* NOTE: This is public/virtual override in Nintendo's kernel. */
|
||||||
void OnFinalizeSynchronizationObject();
|
void OnFinalizeSynchronizationObject();
|
||||||
private:
|
private:
|
||||||
static Result ProcessDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4);
|
static Result ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
|
||||||
public:
|
public:
|
||||||
static Result OnDebugEvent(ams::svc::DebugEvent event, uintptr_t param0 = 0, uintptr_t param1 = 0, uintptr_t param2 = 0, uintptr_t param3 = 0, uintptr_t param4 = 0);
|
static Result OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params);
|
||||||
static Result OnExitProcess(KProcess *process);
|
static Result OnExitProcess(KProcess *process);
|
||||||
static Result OnTerminateProcess(KProcess *process);
|
static Result OnTerminateProcess(KProcess *process);
|
||||||
static Result OnExitThread(KThread *thread);
|
static Result OnExitThread(KThread *thread);
|
||||||
static KEventInfo *CreateDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4, u64 thread_id);
|
static KEventInfo *CreateDebugEvent(ams::svc::DebugEvent event, u64 thread_id, const uintptr_t *params, size_t num_params);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace ams::kern {
|
|||||||
ams::svc::DebugException exception_type;
|
ams::svc::DebugException exception_type;
|
||||||
s32 exception_data_count;
|
s32 exception_data_count;
|
||||||
uintptr_t exception_address;
|
uintptr_t exception_address;
|
||||||
uintptr_t exception_data[4];
|
uintptr_t exception_data[std::max<size_t>(4, cpu::NumCores)];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InfoSystemCall {
|
struct InfoSystemCall {
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ namespace ams::kern {
|
|||||||
class KIoPool final : public KAutoObjectWithSlabHeapAndContainer<KIoPool, KAutoObjectWithList> {
|
class KIoPool final : public KAutoObjectWithSlabHeapAndContainer<KIoPool, KAutoObjectWithList> {
|
||||||
MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject);
|
MESOSPHERE_AUTOOBJECT_TRAITS(KIoPool, KAutoObject);
|
||||||
private:
|
private:
|
||||||
using IoRegionList = util::IntrusiveListMemberTraits<&KIoRegion::m_pool_list_node>::ListType;
|
using IoRegionTree = util::IntrusiveRedBlackTreeBaseTraits<KIoRegion>::TreeType<KIoRegion>;
|
||||||
private:
|
private:
|
||||||
KLightLock m_lock;
|
KLightLock m_lock;
|
||||||
IoRegionList m_io_region_list;
|
IoRegionTree m_io_region_tree;
|
||||||
ams::svc::IoPoolType m_pool_type;
|
ams::svc::IoPoolType m_pool_type;
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -23,11 +23,30 @@ namespace ams::kern {
|
|||||||
class KProcess;
|
class KProcess;
|
||||||
class KIoPool;
|
class KIoPool;
|
||||||
|
|
||||||
class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer<KIoRegion, KAutoObjectWithList> {
|
class KIoRegion final : public KAutoObjectWithSlabHeapAndContainer<KIoRegion, KAutoObjectWithList>, public util::IntrusiveRedBlackTreeBaseNode<KIoRegion> {
|
||||||
MESOSPHERE_AUTOOBJECT_TRAITS(KIoRegion, KAutoObject);
|
MESOSPHERE_AUTOOBJECT_TRAITS(KIoRegion, KAutoObject);
|
||||||
private:
|
private:
|
||||||
friend class KProcess;
|
friend class KProcess;
|
||||||
friend class KIoPool;
|
friend class KIoPool;
|
||||||
|
public:
|
||||||
|
using RedBlackKeyType = KPhysicalAddress;
|
||||||
|
|
||||||
|
static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; }
|
||||||
|
static constexpr ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KIoRegion &v) { return v.GetAddress(); }
|
||||||
|
|
||||||
|
template<typename T> requires (std::same_as<T, KIoRegion> || std::same_as<T, RedBlackKeyType>)
|
||||||
|
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KIoRegion &rhs) {
|
||||||
|
const RedBlackKeyType lval = GetRedBlackKey(lhs);
|
||||||
|
const RedBlackKeyType rval = GetRedBlackKey(rhs);
|
||||||
|
|
||||||
|
if (lval < rval) {
|
||||||
|
return -1;
|
||||||
|
} else if (lval == rval) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
KLightLock m_lock;
|
KLightLock m_lock;
|
||||||
KIoPool *m_pool;
|
KIoPool *m_pool;
|
||||||
@@ -38,7 +57,6 @@ namespace ams::kern {
|
|||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
bool m_is_mapped;
|
bool m_is_mapped;
|
||||||
util::IntrusiveListNode m_process_list_node;
|
util::IntrusiveListNode m_process_list_node;
|
||||||
util::IntrusiveListNode m_pool_list_node;
|
|
||||||
public:
|
public:
|
||||||
explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ }
|
explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ }
|
||||||
|
|
||||||
@@ -51,12 +69,25 @@ namespace ams::kern {
|
|||||||
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);
|
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);
|
||||||
Result Unmap(KProcessAddress address, size_t size);
|
Result Unmap(KProcessAddress address, size_t size);
|
||||||
|
|
||||||
bool Overlaps(KPhysicalAddress address, size_t size) const {
|
constexpr bool Overlaps(KPhysicalAddress address, size_t size) const {
|
||||||
return m_physical_address <= (address + size - 1) && address <= (m_physical_address + m_size - 1);
|
return m_physical_address <= (address + size - 1) && address <= (m_physical_address + m_size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
|
constexpr ALWAYS_INLINE KPhysicalAddress GetAddress() const { return m_physical_address; }
|
||||||
ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; }
|
||||||
|
|
||||||
|
constexpr uintptr_t GetHint() const {
|
||||||
|
/* TODO: Is this architecture specific? */
|
||||||
|
if (m_size >= 2_MB) {
|
||||||
|
return GetInteger(m_physical_address) & (2_MB - 1);
|
||||||
|
} else if (m_size >= 64_KB) {
|
||||||
|
return GetInteger(m_physical_address) & (64_KB - 1);
|
||||||
|
} else if (m_size >= 4_KB) {
|
||||||
|
return GetInteger(m_physical_address) & (4_KB - 1);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,10 +183,10 @@ namespace ams::kern {
|
|||||||
return std::make_tuple(total_size, kernel_size);
|
return std::make_tuple(total_size, kernel_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitializeLinearMemoryAddresses(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start) {
|
static void InitializeLinearMemoryAddresses(u64 phys_to_virt_diff) {
|
||||||
/* Set static differences. */
|
/* Set static differences. */
|
||||||
s_linear_phys_to_virt_diff = GetInteger(linear_virtual_start) - GetInteger(aligned_linear_phys_start);
|
s_linear_phys_to_virt_diff = phys_to_virt_diff;
|
||||||
s_linear_virt_to_phys_diff = GetInteger(aligned_linear_phys_start) - GetInteger(linear_virtual_start);
|
s_linear_virt_to_phys_diff = -phys_to_virt_diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitializeLinearMemoryRegionTrees();
|
static void InitializeLinearMemoryRegionTrees();
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace ams::kern {
|
|||||||
/* Check that the object is closed. */
|
/* Check that the object is closed. */
|
||||||
R_UNLESS(derived->IsServerClosed(), svc::ResultInvalidState());
|
R_UNLESS(derived->IsServerClosed(), svc::ResultInvalidState());
|
||||||
|
|
||||||
return Delete(obj.GetPointerUnsafe(), name);
|
R_RETURN(Delete(obj.GetPointerUnsafe(), name));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Derived> requires std::derived_from<Derived, KAutoObject>
|
template<typename Derived> requires std::derived_from<Derived, KAutoObject>
|
||||||
|
|||||||
@@ -57,11 +57,26 @@ namespace ams::kern {
|
|||||||
using TraversalEntry = KPageTableImpl::TraversalEntry;
|
using TraversalEntry = KPageTableImpl::TraversalEntry;
|
||||||
using TraversalContext = KPageTableImpl::TraversalContext;
|
using TraversalContext = KPageTableImpl::TraversalContext;
|
||||||
|
|
||||||
struct MemoryRange {
|
class MemoryRange {
|
||||||
KPhysicalAddress address;
|
private:
|
||||||
size_t size;
|
KPhysicalAddress m_address;
|
||||||
|
size_t m_size;
|
||||||
|
bool m_heap;
|
||||||
|
public:
|
||||||
|
constexpr MemoryRange() : m_address(Null<KPhysicalAddress>), m_size(0), m_heap(false) { /* ... */ }
|
||||||
|
|
||||||
void Close();
|
void Set(KPhysicalAddress address, size_t size, bool heap) {
|
||||||
|
m_address = address;
|
||||||
|
m_size = size;
|
||||||
|
m_heap = heap;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr KPhysicalAddress GetAddress() const { return m_address; }
|
||||||
|
constexpr size_t GetSize() const { return m_size; }
|
||||||
|
constexpr bool IsHeap() const { return m_heap; }
|
||||||
|
|
||||||
|
void Open();
|
||||||
|
void Close();
|
||||||
};
|
};
|
||||||
protected:
|
protected:
|
||||||
enum MemoryFillValue {
|
enum MemoryFillValue {
|
||||||
@@ -72,13 +87,14 @@ namespace ams::kern {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum OperationType {
|
enum OperationType {
|
||||||
OperationType_Map = 0,
|
OperationType_Map = 0,
|
||||||
OperationType_MapFirst = 1,
|
OperationType_MapFirst = 1,
|
||||||
OperationType_MapGroup = 2,
|
OperationType_MapGroup = 2,
|
||||||
OperationType_Unmap = 3,
|
OperationType_Unmap = 3,
|
||||||
OperationType_ChangePermissions = 4,
|
OperationType_ChangePermissions = 4,
|
||||||
OperationType_ChangePermissionsAndRefresh = 5,
|
OperationType_ChangePermissionsAndRefresh = 5,
|
||||||
OperationType_Separate = 6,
|
OperationType_ChangePermissionsAndRefreshAndFlush = 6,
|
||||||
|
OperationType_Separate = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr size_t MaxPhysicalMapAlignment = 1_GB;
|
static constexpr size_t MaxPhysicalMapAlignment = 1_GB;
|
||||||
@@ -363,7 +379,7 @@ namespace ams::kern {
|
|||||||
Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||||
Result MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm);
|
Result MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm);
|
||||||
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size);
|
Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping);
|
||||||
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||||
Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm);
|
Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm);
|
||||||
Result MapInsecureMemory(KProcessAddress address, size_t size);
|
Result MapInsecureMemory(KProcessAddress address, size_t size);
|
||||||
|
|||||||
@@ -234,11 +234,11 @@ namespace ams::kern {
|
|||||||
KPriorityQueueImpl m_scheduled_queue;
|
KPriorityQueueImpl m_scheduled_queue;
|
||||||
KPriorityQueueImpl m_suggested_queue;
|
KPriorityQueueImpl m_suggested_queue;
|
||||||
private:
|
private:
|
||||||
constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) {
|
static constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) {
|
||||||
affinity &= ~(UINT64_C(1) << core);
|
affinity &= ~(UINT64_C(1) << core);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) {
|
static constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) {
|
||||||
const s32 core = __builtin_ctzll(static_cast<unsigned long long>(affinity));
|
const s32 core = __builtin_ctzll(static_cast<unsigned long long>(affinity));
|
||||||
ClearAffinityBit(affinity, core);
|
ClearAffinityBit(affinity, core);
|
||||||
return core;
|
return core;
|
||||||
|
|||||||
@@ -84,7 +84,9 @@ namespace ams::kern {
|
|||||||
KCapabilities m_capabilities;
|
KCapabilities m_capabilities;
|
||||||
ams::svc::ProgramId m_program_id;
|
ams::svc::ProgramId m_program_id;
|
||||||
u64 m_process_id;
|
u64 m_process_id;
|
||||||
|
#if defined(MESOSPHERE_ENABLE_PROCESS_CREATION_TIME)
|
||||||
s64 m_creation_time;
|
s64 m_creation_time;
|
||||||
|
#endif
|
||||||
KProcessAddress m_code_address;
|
KProcessAddress m_code_address;
|
||||||
size_t m_code_size;
|
size_t m_code_size;
|
||||||
size_t m_main_thread_stack_size;
|
size_t m_main_thread_stack_size;
|
||||||
@@ -108,6 +110,7 @@ namespace ams::kern {
|
|||||||
KWaitObject m_wait_object;
|
KWaitObject m_wait_object;
|
||||||
KThread *m_running_threads[cpu::NumCores];
|
KThread *m_running_threads[cpu::NumCores];
|
||||||
u64 m_running_thread_idle_counts[cpu::NumCores];
|
u64 m_running_thread_idle_counts[cpu::NumCores];
|
||||||
|
u64 m_running_thread_switch_counts[cpu::NumCores];
|
||||||
KThread *m_pinned_threads[cpu::NumCores];
|
KThread *m_pinned_threads[cpu::NumCores];
|
||||||
util::Atomic<s64> m_cpu_time;
|
util::Atomic<s64> m_cpu_time;
|
||||||
util::Atomic<s64> m_num_process_switches;
|
util::Atomic<s64> m_num_process_switches;
|
||||||
@@ -285,9 +288,10 @@ namespace ams::kern {
|
|||||||
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->GetUsedSize() : 0;
|
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->GetUsedSize() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRunningThread(s32 core, KThread *thread, u64 idle_count) {
|
void SetRunningThread(s32 core, KThread *thread, u64 idle_count, u64 switch_count) {
|
||||||
m_running_threads[core] = thread;
|
m_running_threads[core] = thread;
|
||||||
m_running_thread_idle_counts[core] = idle_count;
|
m_running_thread_idle_counts[core] = idle_count;
|
||||||
|
m_running_thread_switch_counts[core] = switch_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearRunningThread(KThread *thread) {
|
void ClearRunningThread(KThread *thread) {
|
||||||
@@ -306,6 +310,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constexpr KThread *GetRunningThread(s32 core) const { return m_running_threads[core]; }
|
constexpr KThread *GetRunningThread(s32 core) const { return m_running_threads[core]; }
|
||||||
constexpr u64 GetRunningThreadIdleCount(s32 core) const { return m_running_thread_idle_counts[core]; }
|
constexpr u64 GetRunningThreadIdleCount(s32 core) const { return m_running_thread_idle_counts[core]; }
|
||||||
|
constexpr u64 GetRunningThreadSwitchCount(s32 core) const { return m_running_thread_switch_counts[core]; }
|
||||||
|
|
||||||
void RegisterThread(KThread *thread);
|
void RegisterThread(KThread *thread);
|
||||||
void UnregisterThread(KThread *thread);
|
void UnregisterThread(KThread *thread);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ namespace ams::kern {
|
|||||||
bool interrupt_task_runnable{false};
|
bool interrupt_task_runnable{false};
|
||||||
bool should_count_idle{false};
|
bool should_count_idle{false};
|
||||||
u64 idle_count{0};
|
u64 idle_count{0};
|
||||||
|
u64 switch_count{0};
|
||||||
KThread *highest_priority_thread{nullptr};
|
KThread *highest_priority_thread{nullptr};
|
||||||
void *idle_thread_stack{nullptr};
|
void *idle_thread_stack{nullptr};
|
||||||
KThread *prev_thread{nullptr};
|
KThread *prev_thread{nullptr};
|
||||||
@@ -67,6 +68,7 @@ namespace ams::kern {
|
|||||||
m_state.interrupt_task_runnable = false;
|
m_state.interrupt_task_runnable = false;
|
||||||
m_state.should_count_idle = false;
|
m_state.should_count_idle = false;
|
||||||
m_state.idle_count = 0;
|
m_state.idle_count = 0;
|
||||||
|
m_state.switch_count = 0;
|
||||||
m_state.idle_thread_stack = nullptr;
|
m_state.idle_thread_stack = nullptr;
|
||||||
m_state.highest_priority_thread = nullptr;
|
m_state.highest_priority_thread = nullptr;
|
||||||
m_state.prev_thread = nullptr;
|
m_state.prev_thread = nullptr;
|
||||||
@@ -93,6 +95,10 @@ namespace ams::kern {
|
|||||||
return m_state.idle_count;
|
return m_state.idle_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE u64 GetSwitchCount() const {
|
||||||
|
return m_state.switch_count;
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE KThread *GetIdleThread() const {
|
ALWAYS_INLINE KThread *GetIdleThread() const {
|
||||||
return m_idle_thread;
|
return m_idle_thread;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
|
||||||
if (this->IsLockedByCurrentThread()) {
|
if (this->IsLockedByCurrentThread()) {
|
||||||
/* If we already own the lock, we can just increment the count. */
|
/* If we already own the lock, the lock count should be > 0. */
|
||||||
|
/* For debug, ensure this is true. */
|
||||||
MESOSPHERE_ASSERT(m_lock_count > 0);
|
MESOSPHERE_ASSERT(m_lock_count > 0);
|
||||||
m_lock_count++;
|
|
||||||
} else {
|
} else {
|
||||||
/* Otherwise, we want to disable scheduling and acquire the spinlock. */
|
/* Otherwise, we want to disable scheduling and acquire the spinlock. */
|
||||||
SchedulerType::DisableScheduling();
|
SchedulerType::DisableScheduling();
|
||||||
@@ -61,10 +61,12 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_ASSERT(m_lock_count == 0);
|
MESOSPHERE_ASSERT(m_lock_count == 0);
|
||||||
MESOSPHERE_ASSERT(m_owner_thread == nullptr);
|
MESOSPHERE_ASSERT(m_owner_thread == nullptr);
|
||||||
|
|
||||||
/* Increment count, take ownership. */
|
/* Take ownership of the lock. */
|
||||||
m_lock_count = 1;
|
|
||||||
m_owner_thread = GetCurrentThreadPointer();
|
m_owner_thread = GetCurrentThreadPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Increment the lock count. */
|
||||||
|
m_lock_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
MESOSPHERE_ALWAYS_INLINE_IF_RELEASE void Unlock() {
|
MESOSPHERE_ALWAYS_INLINE_IF_RELEASE void Unlock() {
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ namespace ams::kern {
|
|||||||
|
|
||||||
struct InitialProcessBinaryLayout;
|
struct InitialProcessBinaryLayout;
|
||||||
|
|
||||||
|
namespace init {
|
||||||
|
|
||||||
|
struct KInitArguments;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ams::kern {
|
namespace ams::kern {
|
||||||
@@ -40,6 +46,8 @@ namespace ams::kern {
|
|||||||
static constinit inline KSpinLock s_random_lock;
|
static constinit inline KSpinLock s_random_lock;
|
||||||
public:
|
public:
|
||||||
class Init {
|
class Init {
|
||||||
|
private:
|
||||||
|
static void CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
||||||
public:
|
public:
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
static size_t GetRealMemorySize();
|
static size_t GetRealMemorySize();
|
||||||
@@ -47,7 +55,7 @@ namespace ams::kern {
|
|||||||
static KPhysicalAddress GetKernelPhysicalBaseAddress(KPhysicalAddress base_address);
|
static KPhysicalAddress GetKernelPhysicalBaseAddress(KPhysicalAddress base_address);
|
||||||
static void GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out);
|
static void GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out);
|
||||||
static bool ShouldIncreaseThreadResourceLimit();
|
static bool ShouldIncreaseThreadResourceLimit();
|
||||||
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
static void TurnOnCpu(u64 core_id, const ams::kern::init::KInitArguments *args);
|
||||||
static size_t GetApplicationPoolSize();
|
static size_t GetApplicationPoolSize();
|
||||||
static size_t GetAppletPoolSize();
|
static size_t GetAppletPoolSize();
|
||||||
static size_t GetMinimumNonSecureSystemPoolSize();
|
static size_t GetMinimumNonSecureSystemPoolSize();
|
||||||
@@ -57,9 +65,11 @@ namespace ams::kern {
|
|||||||
static void GenerateRandom(u64 *dst, size_t count);
|
static void GenerateRandom(u64 *dst, size_t count);
|
||||||
static u64 GenerateRandomRange(u64 min, u64 max);
|
static u64 GenerateRandomRange(u64 min, u64 max);
|
||||||
};
|
};
|
||||||
|
protected:
|
||||||
|
static NOINLINE void InitializePhase1Base(u64 seed);
|
||||||
public:
|
public:
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
static NOINLINE void InitializePhase1(bool skip_target_system = false);
|
static NOINLINE void InitializePhase1();
|
||||||
static NOINLINE void InitializePhase2();
|
static NOINLINE void InitializePhase2();
|
||||||
static NOINLINE u32 GetCreateProcessMemoryPool();
|
static NOINLINE u32 GetCreateProcessMemoryPool();
|
||||||
|
|
||||||
|
|||||||
@@ -108,10 +108,12 @@ namespace ams::kern {
|
|||||||
u8 exception_flags;
|
u8 exception_flags;
|
||||||
bool is_pinned;
|
bool is_pinned;
|
||||||
u8 reserved_2f;
|
u8 reserved_2f;
|
||||||
|
u8 reserved_30[0x10];
|
||||||
KThreadContext context;
|
KThreadContext context;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(util::IsAligned(AMS_OFFSETOF(StackParameters, context), 0x10));
|
static_assert(util::IsAligned(AMS_OFFSETOF(StackParameters, context), 0x10));
|
||||||
|
static_assert(sizeof(StackParameters) == THREAD_STACK_PARAMETERS_SIZE);
|
||||||
|
|
||||||
static_assert(AMS_OFFSETOF(StackParameters, svc_access_flags) == THREAD_STACK_PARAMETERS_SVC_PERMISSION);
|
static_assert(AMS_OFFSETOF(StackParameters, svc_access_flags) == THREAD_STACK_PARAMETERS_SVC_PERMISSION);
|
||||||
static_assert(AMS_OFFSETOF(StackParameters, caller_save_fpu_registers) == THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS);
|
static_assert(AMS_OFFSETOF(StackParameters, caller_save_fpu_registers) == THREAD_STACK_PARAMETERS_CALLER_SAVE_FPU_REGISTERS);
|
||||||
@@ -123,8 +125,10 @@ namespace ams::kern {
|
|||||||
static_assert(AMS_OFFSETOF(StackParameters, exception_flags) == THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS);
|
static_assert(AMS_OFFSETOF(StackParameters, exception_flags) == THREAD_STACK_PARAMETERS_EXCEPTION_FLAGS);
|
||||||
static_assert(AMS_OFFSETOF(StackParameters, is_pinned) == THREAD_STACK_PARAMETERS_IS_PINNED);
|
static_assert(AMS_OFFSETOF(StackParameters, is_pinned) == THREAD_STACK_PARAMETERS_IS_PINNED);
|
||||||
static_assert(AMS_OFFSETOF(StackParameters, reserved_2f) == THREAD_STACK_PARAMETERS_RESERVED_2F);
|
static_assert(AMS_OFFSETOF(StackParameters, reserved_2f) == THREAD_STACK_PARAMETERS_RESERVED_2F);
|
||||||
|
static_assert(AMS_OFFSETOF(StackParameters, reserved_30) == THREAD_STACK_PARAMETERS_RESERVED_30);
|
||||||
static_assert(AMS_OFFSETOF(StackParameters, context) == THREAD_STACK_PARAMETERS_THREAD_CONTEXT);
|
static_assert(AMS_OFFSETOF(StackParameters, context) == THREAD_STACK_PARAMETERS_THREAD_CONTEXT);
|
||||||
|
|
||||||
|
|
||||||
static_assert(ExceptionFlag_IsCallingSvc == THREAD_EXCEPTION_FLAG_IS_CALLING_SVC);
|
static_assert(ExceptionFlag_IsCallingSvc == THREAD_EXCEPTION_FLAG_IS_CALLING_SVC);
|
||||||
static_assert(ExceptionFlag_IsInExceptionHandler == THREAD_EXCEPTION_FLAG_IS_IN_EXCEPTION_HANDLER);
|
static_assert(ExceptionFlag_IsInExceptionHandler == THREAD_EXCEPTION_FLAG_IS_IN_EXCEPTION_HANDLER);
|
||||||
static_assert(ExceptionFlag_IsFpuContextRestoreNeeded == THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED);
|
static_assert(ExceptionFlag_IsFpuContextRestoreNeeded == THREAD_EXCEPTION_FLAG_IS_FPU_CONTEXT_RESTORE_NEEDED);
|
||||||
@@ -197,6 +201,28 @@ namespace ams::kern {
|
|||||||
};
|
};
|
||||||
static_assert(ams::util::HasRedBlackKeyType<ConditionVariableComparator>);
|
static_assert(ams::util::HasRedBlackKeyType<ConditionVariableComparator>);
|
||||||
static_assert(std::same_as<ams::util::RedBlackKeyType<ConditionVariableComparator, void>, ConditionVariableComparator::RedBlackKeyType>);
|
static_assert(std::same_as<ams::util::RedBlackKeyType<ConditionVariableComparator, void>, ConditionVariableComparator::RedBlackKeyType>);
|
||||||
|
|
||||||
|
struct LockWithPriorityInheritanceComparator {
|
||||||
|
struct RedBlackKeyType {
|
||||||
|
s32 m_priority;
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE s32 GetPriority() const {
|
||||||
|
return m_priority;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> requires (std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
|
||||||
|
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThread &rhs) {
|
||||||
|
if (lhs.GetPriority() < rhs.GetPriority()) {
|
||||||
|
/* Sort by priority. */
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(ams::util::HasRedBlackKeyType<LockWithPriorityInheritanceComparator>);
|
||||||
|
static_assert(std::same_as<ams::util::RedBlackKeyType<LockWithPriorityInheritanceComparator, void>, LockWithPriorityInheritanceComparator::RedBlackKeyType>);
|
||||||
private:
|
private:
|
||||||
util::IntrusiveListNode m_process_list_node;
|
util::IntrusiveListNode m_process_list_node;
|
||||||
util::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node;
|
util::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node;
|
||||||
@@ -205,6 +231,67 @@ namespace ams::kern {
|
|||||||
using ConditionVariableThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::m_condvar_arbiter_tree_node>;
|
using ConditionVariableThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::m_condvar_arbiter_tree_node>;
|
||||||
using ConditionVariableThreadTree = ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
|
using ConditionVariableThreadTree = ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
|
||||||
|
|
||||||
|
using LockWithPriorityInheritanceThreadTreeTraits = util::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&KThread::m_condvar_arbiter_tree_node>;
|
||||||
|
using LockWithPriorityInheritanceThreadTree = ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>;
|
||||||
|
public:
|
||||||
|
class LockWithPriorityInheritanceInfo : public KSlabAllocated<LockWithPriorityInheritanceInfo>, public util::IntrusiveListBaseNode<LockWithPriorityInheritanceInfo> {
|
||||||
|
private:
|
||||||
|
LockWithPriorityInheritanceThreadTree m_tree;
|
||||||
|
KProcessAddress m_address_key;
|
||||||
|
KThread *m_owner;
|
||||||
|
u32 m_waiter_count;
|
||||||
|
public:
|
||||||
|
constexpr LockWithPriorityInheritanceInfo() : m_tree(), m_address_key(Null<KProcessAddress>), m_owner(nullptr), m_waiter_count() {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
static LockWithPriorityInheritanceInfo *Create(KProcessAddress address_key) {
|
||||||
|
/* Create a new lock info. */
|
||||||
|
auto *new_lock = LockWithPriorityInheritanceInfo::Allocate();
|
||||||
|
MESOSPHERE_ABORT_UNLESS(new_lock != nullptr);
|
||||||
|
|
||||||
|
/* Set the new lock's address key. */
|
||||||
|
new_lock->m_address_key = address_key;
|
||||||
|
|
||||||
|
return new_lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetOwner(KThread *new_owner) {
|
||||||
|
/* Set new owner. */
|
||||||
|
m_owner = new_owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddWaiter(KThread *waiter) {
|
||||||
|
/* Insert the waiter. */
|
||||||
|
m_tree.insert(*waiter);
|
||||||
|
m_waiter_count++;
|
||||||
|
|
||||||
|
waiter->SetWaitingLockInfo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool RemoveWaiter(KThread *waiter) {
|
||||||
|
m_tree.erase(m_tree.iterator_to(*waiter));
|
||||||
|
|
||||||
|
waiter->SetWaitingLockInfo(nullptr);
|
||||||
|
|
||||||
|
return (--m_waiter_count) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
KThread *GetHighestPriorityWaiter() { return std::addressof(m_tree.front()); }
|
||||||
|
const KThread *GetHighestPriorityWaiter() const { return std::addressof(m_tree.front()); }
|
||||||
|
|
||||||
|
LockWithPriorityInheritanceThreadTree &GetThreadTree() { return m_tree; }
|
||||||
|
const LockWithPriorityInheritanceThreadTree &GetThreadTree() const { return m_tree; }
|
||||||
|
|
||||||
|
constexpr KProcessAddress GetAddressKey() const { return m_address_key; }
|
||||||
|
|
||||||
|
constexpr KThread *GetOwner() const { return m_owner; }
|
||||||
|
|
||||||
|
constexpr u32 GetWaiterCount() const { return m_waiter_count; }
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
using LockWithPriorityInheritanceInfoList = util::IntrusiveListBaseTraits<LockWithPriorityInheritanceInfo>::ListType;
|
||||||
|
|
||||||
ConditionVariableThreadTree *m_condvar_tree;
|
ConditionVariableThreadTree *m_condvar_tree;
|
||||||
uintptr_t m_condvar_key;
|
uintptr_t m_condvar_key;
|
||||||
alignas(16) KThreadContext::CallerSaveFpuRegisters m_caller_save_fpu_registers;
|
alignas(16) KThreadContext::CallerSaveFpuRegisters m_caller_save_fpu_registers;
|
||||||
@@ -224,9 +311,9 @@ namespace ams::kern {
|
|||||||
s64 m_last_scheduled_tick;
|
s64 m_last_scheduled_tick;
|
||||||
QueueEntry m_per_core_priority_queue_entry[cpu::NumCores];
|
QueueEntry m_per_core_priority_queue_entry[cpu::NumCores];
|
||||||
KThreadQueue *m_wait_queue;
|
KThreadQueue *m_wait_queue;
|
||||||
WaiterList m_waiter_list;
|
LockWithPriorityInheritanceInfoList m_held_lock_info_list;
|
||||||
|
LockWithPriorityInheritanceInfo *m_waiting_lock_info;
|
||||||
WaiterList m_pinned_waiter_list;
|
WaiterList m_pinned_waiter_list;
|
||||||
KThread *m_lock_owner;
|
|
||||||
uintptr_t m_debug_params[3];
|
uintptr_t m_debug_params[3];
|
||||||
KAutoObject *m_closed_object;
|
KAutoObject *m_closed_object;
|
||||||
u32 m_address_key_value;
|
u32 m_address_key_value;
|
||||||
@@ -260,8 +347,8 @@ namespace ams::kern {
|
|||||||
m_process_list_node{}, m_condvar_arbiter_tree_node{util::ConstantInitialize}, m_priority{-1}, m_condvar_tree{}, m_condvar_key{},
|
m_process_list_node{}, m_condvar_arbiter_tree_node{util::ConstantInitialize}, m_priority{-1}, m_condvar_tree{}, m_condvar_key{},
|
||||||
m_caller_save_fpu_registers{}, m_virtual_affinity_mask{}, m_physical_affinity_mask{}, m_thread_id{}, m_cpu_time{0}, m_address_key{Null<KProcessAddress>}, m_parent{},
|
m_caller_save_fpu_registers{}, m_virtual_affinity_mask{}, m_physical_affinity_mask{}, m_thread_id{}, m_cpu_time{0}, m_address_key{Null<KProcessAddress>}, m_parent{},
|
||||||
m_kernel_stack_top{}, m_light_ipc_data{}, m_tls_address{Null<KProcessAddress>}, m_tls_heap_address{}, m_activity_pause_lock{}, m_sync_object_buffer{util::ConstantInitialize},
|
m_kernel_stack_top{}, m_light_ipc_data{}, m_tls_address{Null<KProcessAddress>}, m_tls_heap_address{}, m_activity_pause_lock{}, m_sync_object_buffer{util::ConstantInitialize},
|
||||||
m_schedule_count{}, m_last_scheduled_tick{}, m_per_core_priority_queue_entry{}, m_wait_queue{}, m_waiter_list{}, m_pinned_waiter_list{},
|
m_schedule_count{}, m_last_scheduled_tick{}, m_per_core_priority_queue_entry{}, m_wait_queue{}, m_held_lock_info_list{}, m_waiting_lock_info{},
|
||||||
m_lock_owner{}, m_debug_params{}, m_closed_object{}, m_address_key_value{}, m_suspend_request_flags{}, m_suspend_allowed_flags{}, m_synced_index{},
|
m_pinned_waiter_list{}, m_debug_params{}, m_closed_object{}, m_address_key_value{}, m_suspend_request_flags{}, m_suspend_allowed_flags{}, m_synced_index{},
|
||||||
m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{},
|
m_wait_result{svc::ResultNoSynchronizationObject()}, m_debug_exception_result{ResultSuccess()}, m_base_priority{}, m_base_priority_on_unpin{},
|
||||||
m_physical_ideal_core_id{}, m_virtual_ideal_core_id{}, m_num_kernel_waiters{}, m_current_core_id{}, m_core_id{}, m_original_physical_affinity_mask{},
|
m_physical_ideal_core_id{}, m_virtual_ideal_core_id{}, m_num_kernel_waiters{}, m_current_core_id{}, m_core_id{}, m_original_physical_affinity_mask{},
|
||||||
m_original_physical_ideal_core_id{}, m_num_core_migration_disables{}, m_thread_state{}, m_termination_requested{false}, m_wait_cancelled{},
|
m_original_physical_ideal_core_id{}, m_num_core_migration_disables{}, m_thread_state{}, m_termination_requested{false}, m_wait_cancelled{},
|
||||||
@@ -407,6 +494,10 @@ namespace ams::kern {
|
|||||||
void ClearUsermodeExceptionSvcPermissions();
|
void ClearUsermodeExceptionSvcPermissions();
|
||||||
private:
|
private:
|
||||||
void UpdateState();
|
void UpdateState();
|
||||||
|
|
||||||
|
ALWAYS_INLINE void AddHeldLock(LockWithPriorityInheritanceInfo *lock_info);
|
||||||
|
ALWAYS_INLINE LockWithPriorityInheritanceInfo *FindHeldLock(KProcessAddress address_key);
|
||||||
|
|
||||||
ALWAYS_INLINE void AddWaiterImpl(KThread *thread);
|
ALWAYS_INLINE void AddWaiterImpl(KThread *thread);
|
||||||
ALWAYS_INLINE void RemoveWaiterImpl(KThread *thread);
|
ALWAYS_INLINE void RemoveWaiterImpl(KThread *thread);
|
||||||
ALWAYS_INLINE static void RestorePriority(KThread *thread);
|
ALWAYS_INLINE static void RestorePriority(KThread *thread);
|
||||||
@@ -441,6 +532,8 @@ namespace ams::kern {
|
|||||||
constexpr uintptr_t GetAddressArbiterKey() const { return m_condvar_key; }
|
constexpr uintptr_t GetAddressArbiterKey() const { return m_condvar_key; }
|
||||||
|
|
||||||
constexpr void SetConditionVariable(ConditionVariableThreadTree *tree, KProcessAddress address, uintptr_t cv_key, u32 value) {
|
constexpr void SetConditionVariable(ConditionVariableThreadTree *tree, KProcessAddress address, uintptr_t cv_key, u32 value) {
|
||||||
|
MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr);
|
||||||
|
|
||||||
m_condvar_tree = tree;
|
m_condvar_tree = tree;
|
||||||
m_condvar_key = cv_key;
|
m_condvar_key = cv_key;
|
||||||
m_address_key = address;
|
m_address_key = address;
|
||||||
@@ -456,6 +549,8 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr void SetAddressArbiter(ConditionVariableThreadTree *tree, uintptr_t address) {
|
constexpr void SetAddressArbiter(ConditionVariableThreadTree *tree, uintptr_t address) {
|
||||||
|
MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr);
|
||||||
|
|
||||||
m_condvar_tree = tree;
|
m_condvar_tree = tree;
|
||||||
m_condvar_key = address;
|
m_condvar_key = address;
|
||||||
}
|
}
|
||||||
@@ -491,15 +586,17 @@ namespace ams::kern {
|
|||||||
|
|
||||||
void AddWaiter(KThread *thread);
|
void AddWaiter(KThread *thread);
|
||||||
void RemoveWaiter(KThread *thread);
|
void RemoveWaiter(KThread *thread);
|
||||||
KThread *RemoveWaiterByKey(s32 *out_num_waiters, KProcessAddress key);
|
KThread *RemoveWaiterByKey(bool *out_has_waiters, KProcessAddress key);
|
||||||
|
|
||||||
constexpr KProcessAddress GetAddressKey() const { return m_address_key; }
|
constexpr KProcessAddress GetAddressKey() const { return m_address_key; }
|
||||||
constexpr u32 GetAddressKeyValue() const { return m_address_key_value; }
|
constexpr u32 GetAddressKeyValue() const { return m_address_key_value; }
|
||||||
constexpr void SetAddressKey(KProcessAddress key) { m_address_key = key; }
|
constexpr void SetAddressKey(KProcessAddress key) { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); m_address_key = key; }
|
||||||
constexpr void SetAddressKey(KProcessAddress key, u32 val) { m_address_key = key; m_address_key_value = val; }
|
constexpr void SetAddressKey(KProcessAddress key, u32 val) { MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr); m_address_key = key; m_address_key_value = val; }
|
||||||
|
|
||||||
constexpr void SetLockOwner(KThread *owner) { m_lock_owner = owner; }
|
constexpr void SetWaitingLockInfo(LockWithPriorityInheritanceInfo *lock) { m_waiting_lock_info = lock; }
|
||||||
constexpr KThread *GetLockOwner() const { return m_lock_owner; }
|
constexpr LockWithPriorityInheritanceInfo *GetWaitingLockInfo() { return m_waiting_lock_info; }
|
||||||
|
|
||||||
|
constexpr KThread *GetLockOwner() const { return m_waiting_lock_info != nullptr ? m_waiting_lock_info->GetOwner() : nullptr; }
|
||||||
|
|
||||||
constexpr void ClearWaitQueue() { m_wait_queue = nullptr; }
|
constexpr void ClearWaitQueue() { m_wait_queue = nullptr; }
|
||||||
|
|
||||||
@@ -529,8 +626,6 @@ namespace ams::kern {
|
|||||||
constexpr u32 *GetLightSessionData() const { return m_light_ipc_data; }
|
constexpr u32 *GetLightSessionData() const { return m_light_ipc_data; }
|
||||||
constexpr void SetLightSessionData(u32 *data) { m_light_ipc_data = data; }
|
constexpr void SetLightSessionData(u32 *data) { m_light_ipc_data = data; }
|
||||||
|
|
||||||
bool HasWaiters() const { return !m_waiter_list.empty(); }
|
|
||||||
|
|
||||||
constexpr s64 GetLastScheduledTick() const { return m_last_scheduled_tick; }
|
constexpr s64 GetLastScheduledTick() const { return m_last_scheduled_tick; }
|
||||||
constexpr void SetLastScheduledTick(s64 tick) { m_last_scheduled_tick = tick; }
|
constexpr void SetLastScheduledTick(s64 tick) { m_last_scheduled_tick = tick; }
|
||||||
|
|
||||||
|
|||||||
@@ -120,10 +120,6 @@ namespace ams::kern {
|
|||||||
return m_address == rhs;
|
return m_address == rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE bool operator!=(uintptr_t rhs) const {
|
|
||||||
return m_address != rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allow getting the address explicitly, for use in accessors. */
|
/* Allow getting the address explicitly, for use in accessors. */
|
||||||
constexpr ALWAYS_INLINE uintptr_t GetValue() const {
|
constexpr ALWAYS_INLINE uintptr_t GetValue() const {
|
||||||
return m_address;
|
return m_address;
|
||||||
|
|||||||
@@ -164,8 +164,9 @@ namespace ams::kern {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename Derived, typename Base, bool SupportDynamicExpansion = false> requires std::derived_from<Base, KAutoObjectWithList>
|
template<typename Derived, typename Base, bool SupportDynamicExpansion = false>
|
||||||
class KAutoObjectWithSlabHeapAndContainer : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> {
|
class KAutoObjectWithSlabHeapAndContainer : public KAutoObjectWithSlabHeapBase<Derived, Base, SupportDynamicExpansion> {
|
||||||
|
static_assert(std::derived_from<Base, KAutoObjectWithList>);
|
||||||
private:
|
private:
|
||||||
static constinit inline KAutoObjectWithListContainer<Derived> s_container;
|
static constinit inline KAutoObjectWithListContainer<Derived> s_container;
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr inline u32 El0PsrMask = 0xFF0FFE20;
|
|
||||||
|
|
||||||
enum EsrEc : u32 {
|
enum EsrEc : u32 {
|
||||||
EsrEc_Unknown = 0b000000,
|
EsrEc_Unknown = 0b000000,
|
||||||
EsrEc_WaitForInterruptOrEvent = 0b000001,
|
EsrEc_WaitForInterruptOrEvent = 0b000001,
|
||||||
@@ -134,7 +132,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
info->sp = context->sp;
|
info->sp = context->sp;
|
||||||
info->lr = context->x[30];
|
info->lr = context->x[30];
|
||||||
info->pc = context->pc;
|
info->pc = context->pc;
|
||||||
info->pstate = (context->psr & El0PsrMask);
|
info->pstate = (context->psr & cpu::El0Aarch64PsrMask);
|
||||||
info->afsr0 = afsr0;
|
info->afsr0 = afsr0;
|
||||||
info->afsr1 = afsr1;
|
info->afsr1 = afsr1;
|
||||||
info->esr = esr;
|
info->esr = esr;
|
||||||
@@ -151,7 +149,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
info->pc = context->pc;
|
info->pc = context->pc;
|
||||||
info->flags = 1;
|
info->flags = 1;
|
||||||
|
|
||||||
info->status_64.pstate = (context->psr & El0PsrMask);
|
info->status_64.pstate = (context->psr & cpu::El0Aarch32PsrMask);
|
||||||
info->status_64.afsr0 = afsr0;
|
info->status_64.afsr0 = afsr0;
|
||||||
info->status_64.afsr1 = afsr1;
|
info->status_64.afsr1 = afsr1;
|
||||||
info->status_64.esr = esr;
|
info->status_64.esr = esr;
|
||||||
@@ -231,73 +229,71 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
{
|
{
|
||||||
/* Collect additional information based on the ec. */
|
/* Collect additional information based on the ec. */
|
||||||
ams::svc::DebugException exception;
|
uintptr_t params[3] = {};
|
||||||
uintptr_t param2 = 0;
|
|
||||||
uintptr_t param3 = 0;
|
|
||||||
switch (ec) {
|
switch (ec) {
|
||||||
case EsrEc_Unknown:
|
case EsrEc_Unknown:
|
||||||
case EsrEc_IllegalExecution:
|
case EsrEc_IllegalExecution:
|
||||||
case EsrEc_BkptInstruction:
|
case EsrEc_BkptInstruction:
|
||||||
case EsrEc_BrkInstruction:
|
case EsrEc_BrkInstruction:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_UndefinedInstruction;
|
params[0] = ams::svc::DebugException_UndefinedInstruction;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = data;
|
params[2] = data;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_PcAlignmentFault:
|
case EsrEc_PcAlignmentFault:
|
||||||
case EsrEc_SpAlignmentFault:
|
case EsrEc_SpAlignmentFault:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_AlignmentFault;
|
params[0] = ams::svc::DebugException_AlignmentFault;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_Svc32:
|
case EsrEc_Svc32:
|
||||||
case EsrEc_Svc64:
|
case EsrEc_Svc64:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_UndefinedSystemCall;
|
params[0] = ams::svc::DebugException_UndefinedSystemCall;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = (esr & 0xFF);
|
params[2] = (esr & 0xFF);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_BreakPointEl0:
|
case EsrEc_BreakPointEl0:
|
||||||
case EsrEc_SoftwareStepEl0:
|
case EsrEc_SoftwareStepEl0:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_BreakPoint;
|
params[0] = ams::svc::DebugException_BreakPoint;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = ams::svc::BreakPointType_HardwareInstruction;
|
params[2] = ams::svc::BreakPointType_HardwareInstruction;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_WatchPointEl0:
|
case EsrEc_WatchPointEl0:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_BreakPoint;
|
params[0] = ams::svc::DebugException_BreakPoint;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = ams::svc::BreakPointType_HardwareData;
|
params[2] = ams::svc::BreakPointType_HardwareData;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_SErrorInterrupt:
|
case EsrEc_SErrorInterrupt:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_MemorySystemError;
|
params[0] = ams::svc::DebugException_MemorySystemError;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_InstructionAbortEl0:
|
case EsrEc_InstructionAbortEl0:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_InstructionAbort;
|
params[0] = ams::svc::DebugException_InstructionAbort;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_DataAbortEl0:
|
case EsrEc_DataAbortEl0:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_DataAbort;
|
params[0] = ams::svc::DebugException_DataAbort;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process the debug event. */
|
/* Process the debug event. */
|
||||||
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, exception, param2, param3);
|
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
|
||||||
|
|
||||||
/* If we should stop processing the exception, do so. */
|
/* If we should stop processing the exception, do so. */
|
||||||
if (svc::ResultStopProcessingException::Includes(result)) {
|
if (svc::ResultStopProcessingException::Includes(result)) {
|
||||||
@@ -342,7 +338,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
/* If the SVC is handled, handle it. */
|
/* If the SVC is handled, handle it. */
|
||||||
if (!svc::ResultNotHandled::Includes(result)) {
|
if (!svc::ResultNotHandled::Includes(result)) {
|
||||||
/* If we successfully enter jit debug, stop processing the exception. */
|
/* If we successfully enter jit debug, stop processing the exception. */
|
||||||
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, exception, param2, param3)) {
|
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, static_cast<ams::svc::DebugException>(params[0]), params[1], params[2])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -399,7 +395,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
e_ctx->x[30] = info.info64.lr;
|
e_ctx->x[30] = info.info64.lr;
|
||||||
e_ctx->sp = info.info64.sp;
|
e_ctx->sp = info.info64.sp;
|
||||||
e_ctx->pc = info.info64.pc;
|
e_ctx->pc = info.info64.pc;
|
||||||
e_ctx->psr = (info.info64.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask);
|
e_ctx->psr = (info.info64.pstate & cpu::El0Aarch64PsrMask) | (e_ctx->psr & ~cpu::El0Aarch64PsrMask);
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < util::size(info.info32.r); ++i) {
|
for (size_t i = 0; i < util::size(info.info32.r); ++i) {
|
||||||
e_ctx->x[i] = info.info32.r[i];
|
e_ctx->x[i] = info.info32.r[i];
|
||||||
@@ -407,7 +403,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
e_ctx->x[14] = info.info32.lr;
|
e_ctx->x[14] = info.info32.lr;
|
||||||
e_ctx->x[13] = info.info32.sp;
|
e_ctx->x[13] = info.info32.sp;
|
||||||
e_ctx->pc = info.info32.pc;
|
e_ctx->pc = info.info32.pc;
|
||||||
e_ctx->psr = (info.info32.status_64.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask);
|
e_ctx->psr = (info.info32.status_64.pstate & cpu::El0Aarch32PsrMask) | (e_ctx->psr & ~cpu::El0Aarch32PsrMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note that PC was adjusted. */
|
/* Note that PC was adjusted. */
|
||||||
@@ -422,58 +418,56 @@ namespace ams::kern::arch::arm64 {
|
|||||||
GetCurrentThread().RestoreDebugParams(std::addressof(far), std::addressof(esr), std::addressof(data));
|
GetCurrentThread().RestoreDebugParams(std::addressof(far), std::addressof(esr), std::addressof(data));
|
||||||
|
|
||||||
/* Collect additional information based on the ec. */
|
/* Collect additional information based on the ec. */
|
||||||
ams::svc::DebugException exception;
|
uintptr_t params[3] = {};
|
||||||
uintptr_t param2 = 0;
|
|
||||||
uintptr_t param3 = 0;
|
|
||||||
switch ((esr >> 26) & 0x3F) {
|
switch ((esr >> 26) & 0x3F) {
|
||||||
case EsrEc_Unknown:
|
case EsrEc_Unknown:
|
||||||
case EsrEc_IllegalExecution:
|
case EsrEc_IllegalExecution:
|
||||||
case EsrEc_BkptInstruction:
|
case EsrEc_BkptInstruction:
|
||||||
case EsrEc_BrkInstruction:
|
case EsrEc_BrkInstruction:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_UndefinedInstruction;
|
params[0] = ams::svc::DebugException_UndefinedInstruction;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = data;
|
params[2] = data;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_PcAlignmentFault:
|
case EsrEc_PcAlignmentFault:
|
||||||
case EsrEc_SpAlignmentFault:
|
case EsrEc_SpAlignmentFault:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_AlignmentFault;
|
params[0] = ams::svc::DebugException_AlignmentFault;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_Svc32:
|
case EsrEc_Svc32:
|
||||||
case EsrEc_Svc64:
|
case EsrEc_Svc64:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_UndefinedSystemCall;
|
params[0] = ams::svc::DebugException_UndefinedSystemCall;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
param3 = (esr & 0xFF);
|
params[2] = (esr & 0xFF);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_SErrorInterrupt:
|
case EsrEc_SErrorInterrupt:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_MemorySystemError;
|
params[0] = ams::svc::DebugException_MemorySystemError;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_InstructionAbortEl0:
|
case EsrEc_InstructionAbortEl0:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_InstructionAbort;
|
params[0] = ams::svc::DebugException_InstructionAbort;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_DataAbortEl0:
|
case EsrEc_DataAbortEl0:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
exception = ams::svc::DebugException_DataAbort;
|
params[0] = ams::svc::DebugException_DataAbort;
|
||||||
param2 = far;
|
params[1] = far;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process the debug event. */
|
/* Process the debug event. */
|
||||||
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, exception, param2, param3);
|
Result result = KDebug::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
|
||||||
|
|
||||||
/* If the SVC is handled, handle it. */
|
/* If the SVC is handled, handle it. */
|
||||||
if (!svc::ResultNotHandled::Includes(result)) {
|
if (!svc::ResultNotHandled::Includes(result)) {
|
||||||
@@ -483,7 +477,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If we successfully enter jit debug, restore. */
|
/* If we successfully enter jit debug, restore. */
|
||||||
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, exception, param2, param3)) {
|
if (cur_process.EnterJitDebug(ams::svc::DebugEvent_Exception, static_cast<ams::svc::DebugException>(params[0]), params[1], params[2])) {
|
||||||
svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx));
|
svc::RestoreContext(reinterpret_cast<uintptr_t>(e_ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
static_assert(ForbiddenWatchPointFlagsMask == 0xFFFFFFFF00F0E006ul);
|
static_assert(ForbiddenWatchPointFlagsMask == 0xFFFFFFFF00F0E006ul);
|
||||||
|
|
||||||
constexpr inline u32 El0PsrMask = 0xFF0FFE20;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t KDebug::GetProgramCounter(const KThread &thread) {
|
uintptr_t KDebug::GetProgramCounter(const KThread &thread) {
|
||||||
@@ -104,7 +102,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out->lr = e_ctx->x[30];
|
out->lr = e_ctx->x[30];
|
||||||
out->sp = e_ctx->sp;
|
out->sp = e_ctx->sp;
|
||||||
out->pc = e_ctx->pc;
|
out->pc = e_ctx->pc;
|
||||||
out->pstate = (e_ctx->psr & El0PsrMask);
|
out->pstate = (e_ctx->psr & cpu::El0Aarch64PsrMask);
|
||||||
|
|
||||||
/* Adjust PC if we should. */
|
/* Adjust PC if we should. */
|
||||||
if (e_ctx->write == 0 && thread->IsCallingSvc()) {
|
if (e_ctx->write == 0 && thread->IsCallingSvc()) {
|
||||||
@@ -119,7 +117,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out->lr = 0;
|
out->lr = 0;
|
||||||
out->sp = 0;
|
out->sp = 0;
|
||||||
out->pc = e_ctx->pc;
|
out->pc = e_ctx->pc;
|
||||||
out->pstate = (e_ctx->psr & El0PsrMask);
|
out->pstate = (e_ctx->psr & cpu::El0Aarch32PsrMask);
|
||||||
|
|
||||||
/* Adjust PC if we should. */
|
/* Adjust PC if we should. */
|
||||||
if (e_ctx->write == 0 && thread->IsCallingSvc()) {
|
if (e_ctx->write == 0 && thread->IsCallingSvc()) {
|
||||||
@@ -166,7 +164,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
e_ctx->x[30] = ctx.lr;
|
e_ctx->x[30] = ctx.lr;
|
||||||
e_ctx->sp = ctx.sp;
|
e_ctx->sp = ctx.sp;
|
||||||
e_ctx->pc = ctx.pc;
|
e_ctx->pc = ctx.pc;
|
||||||
e_ctx->psr = ((ctx.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask));
|
e_ctx->psr = ((ctx.pstate & cpu::El0Aarch64PsrMask) | (e_ctx->psr & ~cpu::El0Aarch64PsrMask));
|
||||||
e_ctx->tpidr = ctx.tpidr;
|
e_ctx->tpidr = ctx.tpidr;
|
||||||
} else {
|
} else {
|
||||||
e_ctx->x[13] = static_cast<u32>(ctx.r[13]);
|
e_ctx->x[13] = static_cast<u32>(ctx.r[13]);
|
||||||
@@ -174,7 +172,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
e_ctx->x[30] = 0;
|
e_ctx->x[30] = 0;
|
||||||
e_ctx->sp = 0;
|
e_ctx->sp = 0;
|
||||||
e_ctx->pc = static_cast<u32>(ctx.pc);
|
e_ctx->pc = static_cast<u32>(ctx.pc);
|
||||||
e_ctx->psr = ((ctx.pstate & El0PsrMask) | (e_ctx->psr & ~El0PsrMask));
|
e_ctx->psr = ((ctx.pstate & cpu::El0Aarch32PsrMask) | (e_ctx->psr & ~cpu::El0Aarch32PsrMask));
|
||||||
e_ctx->tpidr = ctx.tpidr;
|
e_ctx->tpidr = ctx.tpidr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +249,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result KDebug::BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size) {
|
Result KDebug::BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size) {
|
||||||
R_RETURN(KDebugBase::OnDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_UserBreak, GetProgramCounter(GetCurrentThread()), break_reason, address, size));
|
const uintptr_t params[5] = { ams::svc::DebugException_UserBreak, GetProgramCounter(GetCurrentThread()), break_reason, address, size };
|
||||||
|
R_RETURN(KDebugBase::OnDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MESOSPHERE_SET_HW_BREAK_POINT(ID, FLAGS, VALUE) \
|
#define MESOSPHERE_SET_HW_BREAK_POINT(ID, FLAGS, VALUE) \
|
||||||
|
|||||||
@@ -378,9 +378,11 @@ namespace ams::kern::arch::arm64 {
|
|||||||
case OperationType_MapFirst:
|
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));
|
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:
|
case OperationType_ChangePermissions:
|
||||||
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, page_list, reuse_ll));
|
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, false, page_list, reuse_ll));
|
||||||
case OperationType_ChangePermissionsAndRefresh:
|
case OperationType_ChangePermissionsAndRefresh:
|
||||||
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, page_list, reuse_ll));
|
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, false, page_list, reuse_ll));
|
||||||
|
case OperationType_ChangePermissionsAndRefreshAndFlush:
|
||||||
|
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, true, true, page_list, reuse_ll));
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1233,7 +1235,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_RETURN(this->SeparatePagesImpl(virt_addr, block_size, page_list, reuse_ll));
|
R_RETURN(this->SeparatePagesImpl(virt_addr, block_size, page_list, reuse_ll));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, PageLinkedList *page_list, bool reuse_ll) {
|
Result KPageTable::ChangePermissions(KProcessAddress virt_addr, size_t num_pages, PageTableEntry entry_template, DisableMergeAttribute disable_merge_attr, bool refresh_mapping, bool flush_mapping, PageLinkedList *page_list, bool reuse_ll) {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* Separate pages before we change permissions. */
|
/* Separate pages before we change permissions. */
|
||||||
@@ -1451,8 +1453,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
KScopedSchedulerLock sl;
|
KScopedSchedulerLock sl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, apply the changes as directed, flushing the mappings before they're applied. */
|
/* Finally, apply the changes as directed, flushing the mappings before they're applied (if we should). */
|
||||||
ApplyEntryTemplate(entry_template, ApplyOption_FlushDataCache);
|
ApplyEntryTemplate(entry_template, flush_mapping ? ApplyOption_FlushDataCache : ApplyOption_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We've succeeded, now perform what coalescing we can. */
|
/* We've succeeded, now perform what coalescing we can. */
|
||||||
|
|||||||
@@ -353,12 +353,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
l1_entry->IsPrivilegedExecuteNever(),
|
l1_entry->IsPrivilegedExecuteNever(),
|
||||||
l1_entry->IsContiguous(),
|
l1_entry->IsContiguous(),
|
||||||
!l1_entry->IsGlobal(),
|
!l1_entry->IsGlobal(),
|
||||||
static_cast<int>(l1_entry->GetAccessFlag()),
|
static_cast<int>(l1_entry->GetAccessFlagInteger()),
|
||||||
static_cast<unsigned int>(l1_entry->GetShareable()),
|
static_cast<unsigned int>(l1_entry->GetShareableInteger()),
|
||||||
l1_entry->IsReadOnly(),
|
l1_entry->IsReadOnly(),
|
||||||
l1_entry->IsUserAccessible(),
|
l1_entry->IsUserAccessible(),
|
||||||
l1_entry->IsNonSecure(),
|
l1_entry->IsNonSecure(),
|
||||||
static_cast<int>(l1_entry->GetPageAttribute()),
|
static_cast<int>(l1_entry->GetPageAttributeInteger()),
|
||||||
l1_entry->IsHeadMergeDisabled(),
|
l1_entry->IsHeadMergeDisabled(),
|
||||||
l1_entry->IsHeadAndBodyMergeDisabled(),
|
l1_entry->IsHeadAndBodyMergeDisabled(),
|
||||||
l1_entry->IsTailMergeDisabled());
|
l1_entry->IsTailMergeDisabled());
|
||||||
@@ -398,12 +398,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
l2_entry->IsPrivilegedExecuteNever(),
|
l2_entry->IsPrivilegedExecuteNever(),
|
||||||
l2_entry->IsContiguous(),
|
l2_entry->IsContiguous(),
|
||||||
!l2_entry->IsGlobal(),
|
!l2_entry->IsGlobal(),
|
||||||
static_cast<int>(l2_entry->GetAccessFlag()),
|
static_cast<int>(l2_entry->GetAccessFlagInteger()),
|
||||||
static_cast<unsigned int>(l2_entry->GetShareable()),
|
static_cast<unsigned int>(l2_entry->GetShareableInteger()),
|
||||||
l2_entry->IsReadOnly(),
|
l2_entry->IsReadOnly(),
|
||||||
l2_entry->IsUserAccessible(),
|
l2_entry->IsUserAccessible(),
|
||||||
l2_entry->IsNonSecure(),
|
l2_entry->IsNonSecure(),
|
||||||
static_cast<int>(l2_entry->GetPageAttribute()),
|
static_cast<int>(l2_entry->GetPageAttributeInteger()),
|
||||||
l2_entry->IsHeadMergeDisabled(),
|
l2_entry->IsHeadMergeDisabled(),
|
||||||
l2_entry->IsHeadAndBodyMergeDisabled(),
|
l2_entry->IsHeadAndBodyMergeDisabled(),
|
||||||
l2_entry->IsTailMergeDisabled());
|
l2_entry->IsTailMergeDisabled());
|
||||||
@@ -443,12 +443,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
l3_entry->IsPrivilegedExecuteNever(),
|
l3_entry->IsPrivilegedExecuteNever(),
|
||||||
l3_entry->IsContiguous(),
|
l3_entry->IsContiguous(),
|
||||||
!l3_entry->IsGlobal(),
|
!l3_entry->IsGlobal(),
|
||||||
static_cast<int>(l3_entry->GetAccessFlag()),
|
static_cast<int>(l3_entry->GetAccessFlagInteger()),
|
||||||
static_cast<unsigned int>(l3_entry->GetShareable()),
|
static_cast<unsigned int>(l3_entry->GetShareableInteger()),
|
||||||
l3_entry->IsReadOnly(),
|
l3_entry->IsReadOnly(),
|
||||||
l3_entry->IsUserAccessible(),
|
l3_entry->IsUserAccessible(),
|
||||||
l3_entry->IsNonSecure(),
|
l3_entry->IsNonSecure(),
|
||||||
static_cast<int>(l3_entry->GetPageAttribute()),
|
static_cast<int>(l3_entry->GetPageAttributeInteger()),
|
||||||
l3_entry->IsHeadMergeDisabled(),
|
l3_entry->IsHeadMergeDisabled(),
|
||||||
l3_entry->IsHeadAndBodyMergeDisabled(),
|
l3_entry->IsHeadAndBodyMergeDisabled(),
|
||||||
l3_entry->IsTailMergeDisabled());
|
l3_entry->IsTailMergeDisabled());
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ namespace ams::kern::arch::arm64 {
|
|||||||
/* Send KDebug event for this thread's creation. */
|
/* Send KDebug event for this thread's creation. */
|
||||||
{
|
{
|
||||||
KScopedInterruptEnable ei;
|
KScopedInterruptEnable ei;
|
||||||
KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, GetCurrentThread().GetId(), GetInteger(GetCurrentThread().GetThreadLocalRegionAddress()));
|
|
||||||
|
const uintptr_t params[2] = { GetCurrentThread().GetId(), GetInteger(GetCurrentThread().GetThreadLocalRegionAddress()) };
|
||||||
|
KDebug::OnDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle any pending dpc. */
|
/* Handle any pending dpc. */
|
||||||
@@ -40,8 +42,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr inline u32 El0PsrMask = 0xFF0FFE20;
|
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsFpuEnabled() {
|
ALWAYS_INLINE bool IsFpuEnabled() {
|
||||||
return cpu::ArchitecturalFeatureAccessControlRegisterAccessor().IsFpEnabled();
|
return cpu::ArchitecturalFeatureAccessControlRegisterAccessor().IsFpEnabled();
|
||||||
}
|
}
|
||||||
@@ -96,8 +96,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
/* SP */
|
/* SP */
|
||||||
/* | */
|
/* | */
|
||||||
/* v */
|
/* v */
|
||||||
/* | u64 argument | u64 entrypoint | KThread::StackParameters (size 0x130) | */
|
/* | u64 argument | u64 entrypoint | KThread::StackParameters (size 0x140) | */
|
||||||
static_assert(sizeof(KThread::StackParameters) == 0x130);
|
static_assert(sizeof(KThread::StackParameters) == 0x140);
|
||||||
|
|
||||||
u64 *stack = GetPointer<u64>(sp);
|
u64 *stack = GetPointer<u64>(sp);
|
||||||
*(--stack) = GetInteger(pc);
|
*(--stack) = GetInteger(pc);
|
||||||
@@ -191,7 +191,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
out->lr = e_ctx->x[30];
|
out->lr = e_ctx->x[30];
|
||||||
out->sp = e_ctx->sp;
|
out->sp = e_ctx->sp;
|
||||||
out->pc = e_ctx->pc;
|
out->pc = e_ctx->pc;
|
||||||
out->pstate = e_ctx->psr & El0PsrMask;
|
out->pstate = e_ctx->psr & cpu::El0Aarch64PsrMask;
|
||||||
|
|
||||||
/* Get the thread's general purpose registers. */
|
/* Get the thread's general purpose registers. */
|
||||||
if (thread->IsCallingSvc()) {
|
if (thread->IsCallingSvc()) {
|
||||||
@@ -227,7 +227,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
} else {
|
} else {
|
||||||
/* Set special registers. */
|
/* Set special registers. */
|
||||||
out->pc = static_cast<u32>(e_ctx->pc);
|
out->pc = static_cast<u32>(e_ctx->pc);
|
||||||
out->pstate = e_ctx->psr & El0PsrMask;
|
out->pstate = e_ctx->psr & cpu::El0Aarch32PsrMask;
|
||||||
|
|
||||||
/* Get the thread's general purpose registers. */
|
/* Get the thread's general purpose registers. */
|
||||||
for (size_t i = 0; i < 15; ++i) {
|
for (size_t i = 0; i < 15; ++i) {
|
||||||
|
|||||||
@@ -596,8 +596,11 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory32BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for read failure. */
|
||||||
|
adr x10, 4f
|
||||||
|
|
||||||
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
||||||
adr x30, 4f
|
mov x30, x10
|
||||||
|
|
||||||
/* Read the word from io. */
|
/* Read the word from io. */
|
||||||
ldtr w9, [x5]
|
ldtr w9, [x5]
|
||||||
@@ -643,8 +646,11 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17ReadIoMemory16BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for read failure. */
|
||||||
|
adr x10, 4f
|
||||||
|
|
||||||
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
||||||
adr x30, 4f
|
mov x30, x10
|
||||||
|
|
||||||
/* Read the word from io. */
|
/* Read the word from io. */
|
||||||
ldtrh w9, [x5]
|
ldtrh w9, [x5]
|
||||||
@@ -690,8 +696,11 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess16ReadIoMemory8BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for read failure. */
|
||||||
|
adr x10, 4f
|
||||||
|
|
||||||
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
1: /* Set our return address so that on read failure we continue as though we read -1. */
|
||||||
adr x30, 4f
|
mov x30, x10
|
||||||
|
|
||||||
/* Read the word from io. */
|
/* Read the word from io. */
|
||||||
ldtrb w9, [x5]
|
ldtrb w9, [x5]
|
||||||
@@ -737,11 +746,14 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory32BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for failure. */
|
||||||
|
adr x10, 2f
|
||||||
|
|
||||||
1: /* Read the word from normal memory. */
|
1: /* Read the word from normal memory. */
|
||||||
ldtr w9, [x5]
|
ldtr w9, [x5]
|
||||||
|
|
||||||
/* Set our return address so that on read failure we continue. */
|
/* Set our return address so that on failure we continue. */
|
||||||
adr x30, 2f
|
mov x30, x10
|
||||||
|
|
||||||
/* Write the word to io. */
|
/* Write the word to io. */
|
||||||
sttr w9, [x5]
|
sttr w9, [x5]
|
||||||
@@ -779,11 +791,14 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess18WriteIoMemory16BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for failure. */
|
||||||
|
adr x10, 2f
|
||||||
|
|
||||||
1: /* Read the word from normal memory. */
|
1: /* Read the word from normal memory. */
|
||||||
ldtrh w9, [x5]
|
ldtrh w9, [x5]
|
||||||
|
|
||||||
/* Set our return address so that on read failure we continue. */
|
/* Set our return address so that on failure we continue. */
|
||||||
adr x30, 2f
|
mov x30, x10
|
||||||
|
|
||||||
/* Write the word to io. */
|
/* Write the word to io. */
|
||||||
sttrh w9, [x5]
|
sttrh w9, [x5]
|
||||||
@@ -821,11 +836,14 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess17WriteIoMemory8BitEPvPKvm:
|
|||||||
/* Save our return address. */
|
/* Save our return address. */
|
||||||
mov x8, x30
|
mov x8, x30
|
||||||
|
|
||||||
|
/* Prepare return address for failure. */
|
||||||
|
adr x10, 2f
|
||||||
|
|
||||||
1: /* Read the word from normal memory. */
|
1: /* Read the word from normal memory. */
|
||||||
ldtrb w9, [x5]
|
ldtrb w9, [x5]
|
||||||
|
|
||||||
/* Set our return address so that on read failure we continue. */
|
/* Set our return address so that on failure we continue. */
|
||||||
adr x30, 2f
|
mov x30, x10
|
||||||
|
|
||||||
/* Write the word to io. */
|
/* Write the word to io. */
|
||||||
sttrb w9, [x5]
|
sttrb w9, [x5]
|
||||||
|
|||||||
@@ -1133,17 +1133,17 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
size_t cur_size;
|
size_t cur_size;
|
||||||
{
|
{
|
||||||
/* Get the current contiguous range. */
|
/* Get the current contiguous range. */
|
||||||
KPageTableBase::MemoryRange contig_range = { .address = Null<KPhysicalAddress>, .size = 0 };
|
KPageTableBase::MemoryRange contig_range;
|
||||||
R_TRY(page_table->OpenMemoryRangeForMapDeviceAddressSpace(std::addressof(contig_range), process_address + mapped_size, size - mapped_size, ConvertToKMemoryPermission(device_perm), is_aligned));
|
R_TRY(page_table->OpenMemoryRangeForMapDeviceAddressSpace(std::addressof(contig_range), process_address + mapped_size, size - mapped_size, ConvertToKMemoryPermission(device_perm), is_aligned));
|
||||||
|
|
||||||
/* Ensure we close the range when we're done. */
|
/* Ensure we close the range when we're done. */
|
||||||
ON_SCOPE_EXIT { contig_range.Close(); };
|
ON_SCOPE_EXIT { contig_range.Close(); };
|
||||||
|
|
||||||
/* Get the current size. */
|
/* Get the current size. */
|
||||||
cur_size = contig_range.size;
|
cur_size = contig_range.GetSize();
|
||||||
|
|
||||||
/* Map the device page. */
|
/* Map the device page. */
|
||||||
R_TRY(this->MapDevicePage(contig_range.address, contig_range.size, cur_addr, device_perm));
|
R_TRY(this->MapDevicePage(contig_range.GetAddress(), cur_size, cur_addr, device_perm));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
@@ -1288,7 +1288,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
|
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
|
||||||
|
|
||||||
/* We need to traverse the ranges that make up our mapping, to make sure they're all good. Start by getting a contiguous range. */
|
/* We need to traverse the ranges that make up our mapping, to make sure they're all good. Start by getting a contiguous range. */
|
||||||
KPageTableBase::MemoryRange contig_range = { .address = Null<KPhysicalAddress>, .size = 0 };
|
KPageTableBase::MemoryRange contig_range;
|
||||||
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), process_address, size))) {
|
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), process_address, size))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1300,8 +1300,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Walk the directory. */
|
/* Walk the directory. */
|
||||||
KProcessAddress cur_process_address = process_address;
|
KProcessAddress cur_process_address = process_address;
|
||||||
size_t remaining_size = size;
|
size_t remaining_size = size;
|
||||||
KPhysicalAddress cur_phys_address = contig_range.address;
|
KPhysicalAddress cur_phys_address = contig_range.GetAddress();
|
||||||
size_t remaining_in_range = contig_range.size;
|
size_t remaining_in_range = contig_range.GetSize();
|
||||||
bool first = true;
|
bool first = true;
|
||||||
u32 first_attr = 0;
|
u32 first_attr = 0;
|
||||||
while (remaining_size > 0) {
|
while (remaining_size > 0) {
|
||||||
@@ -1347,8 +1347,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
}
|
}
|
||||||
range_open = true;
|
range_open = true;
|
||||||
|
|
||||||
cur_phys_address = contig_range.address;
|
cur_phys_address = contig_range.GetAddress();
|
||||||
remaining_in_range = contig_range.size;
|
remaining_in_range = contig_range.GetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the physical address is expected. */
|
/* Check that the physical address is expected. */
|
||||||
@@ -1390,8 +1390,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
}
|
}
|
||||||
range_open = true;
|
range_open = true;
|
||||||
|
|
||||||
cur_phys_address = contig_range.address;
|
cur_phys_address = contig_range.GetAddress();
|
||||||
remaining_in_range = contig_range.size;
|
remaining_in_range = contig_range.GetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the physical address is expected, and there's enough in the range. */
|
/* Check that the physical address is expected, and there's enough in the range. */
|
||||||
|
|||||||
@@ -18,6 +18,12 @@
|
|||||||
#include "kern_secure_monitor.hpp"
|
#include "kern_secure_monitor.hpp"
|
||||||
#include "kern_lps_driver.hpp"
|
#include "kern_lps_driver.hpp"
|
||||||
|
|
||||||
|
namespace ams::kern::init {
|
||||||
|
|
||||||
|
void StartOtherCore(const ams::kern::init::KInitArguments *init_args);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace ams::kern::board::nintendo::nx {
|
namespace ams::kern::board::nintendo::nx {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -67,15 +73,10 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
constinit KLightLock g_request_lock;
|
constinit KLightLock g_request_lock;
|
||||||
constinit KLightLock g_cv_lock;
|
constinit KLightLock g_cv_lock;
|
||||||
constinit KLightConditionVariable g_cv{util::ConstantInitialize};
|
constinit KLightConditionVariable g_cv{util::ConstantInitialize};
|
||||||
constinit KPhysicalAddress g_sleep_buffer_phys_addrs[cpu::NumCores];
|
|
||||||
alignas(1_KB) constinit u64 g_sleep_buffers[cpu::NumCores][1_KB / sizeof(u64)];
|
alignas(1_KB) constinit u64 g_sleep_buffers[cpu::NumCores][1_KB / sizeof(u64)];
|
||||||
|
constinit ams::kern::init::KInitArguments g_sleep_init_arguments[cpu::NumCores];
|
||||||
constinit SavedSystemRegisters g_sleep_system_registers[cpu::NumCores] = {};
|
constinit SavedSystemRegisters g_sleep_system_registers[cpu::NumCores] = {};
|
||||||
|
|
||||||
void PowerOnCpu(int core_id, KPhysicalAddress entry_phys_addr, u64 context_id) {
|
|
||||||
/* Request the secure monitor power on the core. */
|
|
||||||
::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor, true>(cpu::MultiprocessorAffinityRegisterAccessor().GetCpuOnArgument() | core_id, GetInteger(entry_phys_addr), context_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitOtherCpuPowerOff() {
|
void WaitOtherCpuPowerOff() {
|
||||||
constexpr u64 PmcPhysicalAddress = 0x7000E400;
|
constexpr u64 PmcPhysicalAddress = 0x7000E400;
|
||||||
constexpr u32 PWRGATE_STATUS_CE123_MASK = ((1u << 3) - 1) << 9;
|
constexpr u32 PWRGATE_STATUS_CE123_MASK = ((1u << 3) - 1) << 9;
|
||||||
@@ -473,18 +474,20 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSleepManager::ProcessRequests(uintptr_t buffer) {
|
void KSleepManager::ProcessRequests(uintptr_t sleep_buffer) {
|
||||||
const auto target_fw = GetTargetFirmware();
|
const auto target_fw = GetTargetFirmware();
|
||||||
const s32 core_id = GetCurrentCoreId();
|
const s32 core_id = GetCurrentCoreId();
|
||||||
KPhysicalAddress resume_entry_phys_addr = Null<KPhysicalAddress>;
|
|
||||||
|
ams::kern::init::KInitArguments * const init_args = g_sleep_init_arguments + core_id;
|
||||||
|
KPhysicalAddress start_core_phys_addr = Null<KPhysicalAddress>;
|
||||||
|
KPhysicalAddress init_args_phys_addr = Null<KPhysicalAddress>;
|
||||||
|
|
||||||
/* Get the physical addresses we'll need. */
|
/* Get the physical addresses we'll need. */
|
||||||
{
|
{
|
||||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(g_sleep_buffer_phys_addrs[core_id]), KProcessAddress(buffer)));
|
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(start_core_phys_addr), KProcessAddress(&::ams::kern::init::StartOtherCore)));
|
||||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(resume_entry_phys_addr), KProcessAddress(&::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry)));
|
MESOSPHERE_ABORT_UNLESS(Kernel::GetKernelPageTable().GetPhysicalAddress(std::addressof(init_args_phys_addr), KProcessAddress(init_args)));
|
||||||
|
|
||||||
}
|
}
|
||||||
const KPhysicalAddress sleep_buffer_phys_addr = g_sleep_buffer_phys_addrs[core_id];
|
|
||||||
const u64 target_core_mask = (1ul << core_id);
|
const u64 target_core_mask = (1ul << core_id);
|
||||||
|
|
||||||
const bool use_legacy_lps_driver = target_fw < TargetFirmware_2_0_0;
|
const bool use_legacy_lps_driver = target_fw < TargetFirmware_2_0_0;
|
||||||
@@ -547,15 +550,29 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Save the interrupt manager's state. */
|
/* Save the interrupt manager's state. */
|
||||||
Kernel::GetInterruptManager().Save(core_id);
|
Kernel::GetInterruptManager().Save(core_id);
|
||||||
|
|
||||||
|
/* Setup the initial arguments. */
|
||||||
|
{
|
||||||
|
init_args->ttbr0 = cpu::GetTtbr0El1();
|
||||||
|
init_args->ttbr1 = cpu::GetTtbr1El1();
|
||||||
|
init_args->tcr = cpu::GetTcrEl1();
|
||||||
|
init_args->mair = cpu::GetMairEl1();
|
||||||
|
init_args->cpuactlr = cpu::GetCpuActlrEl1();
|
||||||
|
init_args->cpuectlr = cpu::GetCpuEctlrEl1();
|
||||||
|
init_args->sctlr = cpu::GetSctlrEl1();
|
||||||
|
init_args->sp = 0;
|
||||||
|
init_args->entrypoint = reinterpret_cast<uintptr_t>(::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry);
|
||||||
|
init_args->argument = sleep_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/* Ensure that all cores get to this point before continuing. */
|
/* Ensure that all cores get to this point before continuing. */
|
||||||
cpu::SynchronizeAllCores();
|
cpu::SynchronizeAllCores();
|
||||||
|
|
||||||
/* Log that the core is going to sleep. */
|
/* Log that the core is going to sleep. */
|
||||||
MESOSPHERE_LOG("Core[%d]: Going to sleep, buffer = %010lx\n", core_id, GetInteger(sleep_buffer_phys_addr));
|
MESOSPHERE_LOG("Core[%d]: Going to sleep, buffer = %010lx\n", core_id, sleep_buffer);
|
||||||
|
|
||||||
/* If we're on a core other than zero, we can just invoke the sleep handler. */
|
/* If we're on a core other than zero, we can just invoke the sleep handler. */
|
||||||
if (core_id != 0) {
|
if (core_id != 0) {
|
||||||
CpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr));
|
CpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr));
|
||||||
} else {
|
} else {
|
||||||
/* Wait for all other cores to be powered off. */
|
/* Wait for all other cores to be powered off. */
|
||||||
WaitOtherCpuPowerOff();
|
WaitOtherCpuPowerOff();
|
||||||
@@ -574,9 +591,9 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Invoke the sleep handler. */
|
/* Invoke the sleep handler. */
|
||||||
if (!use_legacy_lps_driver) {
|
if (!use_legacy_lps_driver) {
|
||||||
/* When not using the legacy driver, invoke directly. */
|
/* When not using the legacy driver, invoke directly. */
|
||||||
CpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr));
|
CpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr));
|
||||||
} else {
|
} else {
|
||||||
lps::InvokeCpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr));
|
lps::InvokeCpuSleepHandler(sleep_buffer, GetInteger(start_core_phys_addr), GetInteger(init_args_phys_addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore the debug log state. */
|
/* Restore the debug log state. */
|
||||||
@@ -586,8 +603,10 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
MESOSPHERE_LOG("Exiting SC7\n");
|
MESOSPHERE_LOG("Exiting SC7\n");
|
||||||
|
|
||||||
/* Wake up the other cores. */
|
/* Wake up the other cores. */
|
||||||
|
cpu::MultiprocessorAffinityRegisterAccessor mpidr;
|
||||||
|
const auto arg = mpidr.GetCpuOnArgument();
|
||||||
for (s32 i = 1; i < static_cast<s32>(cpu::NumCores); ++i) {
|
for (s32 i = 1; i < static_cast<s32>(cpu::NumCores); ++i) {
|
||||||
PowerOnCpu(i, resume_entry_phys_addr, GetInteger(g_sleep_buffer_phys_addrs[i]));
|
KSystemControl::Init::TurnOnCpu(arg | i, g_sleep_init_arguments + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,14 +22,12 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
private:
|
private:
|
||||||
static void ResumeEntry(uintptr_t arg);
|
static void ResumeEntry(uintptr_t arg);
|
||||||
|
|
||||||
static void InvalidateDataCacheForResumeEntry(uintptr_t level);
|
|
||||||
|
|
||||||
static void ProcessRequests(uintptr_t buffer);
|
static void ProcessRequests(uintptr_t buffer);
|
||||||
public:
|
public:
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
static void SleepSystem();
|
static void SleepSystem();
|
||||||
public:
|
public:
|
||||||
static void CpuSleepHandler(uintptr_t arg, uintptr_t entry);
|
static void CpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_args);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,14 +22,14 @@
|
|||||||
mov reg, #(((val) >> 0x00) & 0xFFFF); \
|
mov reg, #(((val) >> 0x00) & 0xFFFF); \
|
||||||
movk reg, #(((val) >> 0x10) & 0xFFFF), lsl#16
|
movk reg, #(((val) >> 0x10) & 0xFFFF), lsl#16
|
||||||
|
|
||||||
/* ams::kern::board::nintendo::nx::KSleepManager::CpuSleepHandler(uintptr_t arg, uintptr_t entry) */
|
/* ams::kern::board::nintendo::nx::KSleepManager::CpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg) */
|
||||||
.section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm, "ax", %progbits
|
.section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm, "ax", %progbits
|
||||||
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm
|
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm
|
||||||
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm, %function
|
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm, %function
|
||||||
_ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
|
_ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmmm:
|
||||||
/* Save arguments. */
|
/* Save arguments. */
|
||||||
mov x16, x0
|
mov x16, x1
|
||||||
mov x17, x1
|
mov x17, x2
|
||||||
|
|
||||||
/* Enable access to FPU registers. */
|
/* Enable access to FPU registers. */
|
||||||
mrs x1, cpacr_el1
|
mrs x1, cpacr_el1
|
||||||
@@ -74,28 +74,8 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
|
|||||||
stp q28, q29, [x0], #0x20
|
stp q28, q29, [x0], #0x20
|
||||||
stp q30, q31, [x0], #0x20
|
stp q30, q31, [x0], #0x20
|
||||||
|
|
||||||
/* Save cpuactlr/cpuectlr. */
|
/* Save tpidr/cntv_cval_el0. */
|
||||||
mrs x1, cpuectlr_el1
|
mrs x1, tpidr_el1
|
||||||
mrs x2, cpuactlr_el1
|
|
||||||
stp x1, x2, [x0], #0x10
|
|
||||||
|
|
||||||
/* Save ttbr0/ttbr1. */
|
|
||||||
mrs x1, ttbr0_el1
|
|
||||||
mrs x2, ttbr1_el1
|
|
||||||
stp x1, x2, [x0], #0x10
|
|
||||||
|
|
||||||
/* Save tcr/mair. */
|
|
||||||
mrs x1, tcr_el1
|
|
||||||
mrs x2, mair_el1
|
|
||||||
stp x1, x2, [x0], #0x10
|
|
||||||
|
|
||||||
/* Save sctlr/tpidr. */
|
|
||||||
mrs x1, sctlr_el1
|
|
||||||
mrs x2, tpidr_el1
|
|
||||||
stp x1, x2, [x0], #0x10
|
|
||||||
|
|
||||||
/* Save the virtual resumption entrypoint and cntv_cval_el0. */
|
|
||||||
adr x1, 77f
|
|
||||||
mrs x2, cntv_cval_el0
|
mrs x2, cntv_cval_el0
|
||||||
stp x1, x2, [x0], #0x10
|
stp x1, x2, [x0], #0x10
|
||||||
|
|
||||||
@@ -114,8 +94,8 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
|
|||||||
1: /* Suspend. */
|
1: /* Suspend. */
|
||||||
LOAD_IMMEDIATE_32(x0, 0xC4000001)
|
LOAD_IMMEDIATE_32(x0, 0xC4000001)
|
||||||
LOAD_IMMEDIATE_32(x1, 0x0201001B)
|
LOAD_IMMEDIATE_32(x1, 0x0201001B)
|
||||||
mov x2, x17
|
mov x2, x16
|
||||||
mov x3, x16
|
mov x3, x17
|
||||||
smc #1
|
smc #1
|
||||||
0: b 0b
|
0: b 0b
|
||||||
|
|
||||||
@@ -124,65 +104,6 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager15CpuSleepHandlerEmm:
|
|||||||
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm
|
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm
|
||||||
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, %function
|
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm, %function
|
||||||
_ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
|
_ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
|
||||||
/* Mask interrupts. */
|
|
||||||
msr daifset, #0xF
|
|
||||||
|
|
||||||
/* Save the argument. */
|
|
||||||
mov x21, x0
|
|
||||||
|
|
||||||
/* Check that we're at the correct exception level. */
|
|
||||||
mrs x0, currentel
|
|
||||||
|
|
||||||
/* Check if we're EL1. */
|
|
||||||
cmp x0, #0x4
|
|
||||||
b.eq 3f
|
|
||||||
|
|
||||||
/* Check if we're EL2. */
|
|
||||||
cmp x0, #0x8
|
|
||||||
b.eq 2f
|
|
||||||
|
|
||||||
1: /* We're running at EL3. */
|
|
||||||
b 1b
|
|
||||||
|
|
||||||
2: /* We're running at EL2. */
|
|
||||||
b 2b
|
|
||||||
|
|
||||||
3: /* We're running at EL1. */
|
|
||||||
|
|
||||||
/* Invalidate the L1 cache. */
|
|
||||||
mov x0, #0
|
|
||||||
bl _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
|
|
||||||
|
|
||||||
/* Get the current core id. */
|
|
||||||
mrs x0, mpidr_el1
|
|
||||||
and x0, x0, #0xFF
|
|
||||||
|
|
||||||
/* If we're on core0, we want to invalidate the L2 cache. */
|
|
||||||
cbnz x0, 4f
|
|
||||||
|
|
||||||
mov x0, #1
|
|
||||||
bl _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
|
|
||||||
|
|
||||||
4: /* Invalidate the L1 cache. */
|
|
||||||
mov x0, #0
|
|
||||||
bl _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
|
|
||||||
|
|
||||||
/* Invalidate the instruction cache. */
|
|
||||||
ic ialluis
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* Invalidate the entire tlb. */
|
|
||||||
tlbi vmalle1is
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* Switch to sp 1. */
|
|
||||||
msr spsel, #1
|
|
||||||
|
|
||||||
/* Prepare to restore the saved context. */
|
|
||||||
mov x0, x21
|
|
||||||
|
|
||||||
/* Enable access to FPU registers. */
|
/* Enable access to FPU registers. */
|
||||||
mrs x1, cpacr_el1
|
mrs x1, cpacr_el1
|
||||||
orr x1, x1, #0x100000
|
orr x1, x1, #0x100000
|
||||||
@@ -226,121 +147,12 @@ _ZN3ams4kern5board8nintendo2nx13KSleepManager11ResumeEntryEm:
|
|||||||
ldp q28, q29, [x0], #0x20
|
ldp q28, q29, [x0], #0x20
|
||||||
ldp q30, q31, [x0], #0x20
|
ldp q30, q31, [x0], #0x20
|
||||||
|
|
||||||
/* Restore cpuactlr/cpuectlr. */
|
/* Restore tpidr/cntv_cval_el0. */
|
||||||
ldp x1, x2, [x0], #0x10
|
ldp x1, x2, [x0], #0x10
|
||||||
mrs x3, cpuectlr_el1
|
msr tpidr_el1, x1
|
||||||
cmp x1, x3
|
msr cntv_cval_el0, x2
|
||||||
5: b.ne 5b
|
|
||||||
mrs x3, cpuactlr_el1
|
|
||||||
cmp x2, x3
|
|
||||||
6: b.ne 6b
|
|
||||||
|
|
||||||
/* Restore ttbr0/ttbr1. */
|
|
||||||
ldp x1, x2, [x0], #0x10
|
|
||||||
msr ttbr0_el1, x1
|
|
||||||
msr ttbr1_el1, x2
|
|
||||||
|
|
||||||
/* Restore tcr/mair. */
|
|
||||||
ldp x1, x2, [x0], #0x10
|
|
||||||
msr tcr_el1, x1
|
|
||||||
msr mair_el1, x2
|
|
||||||
|
|
||||||
/* Get sctlr, tpidr, the entrypoint, and cntv_cval_el0. */
|
|
||||||
ldp x1, x2, [x0], #0x10
|
|
||||||
ldp x3, x4, [x0], #0x10
|
|
||||||
|
|
||||||
/* Set the global context back into x18/tpidr. */
|
|
||||||
msr tpidr_el1, x2
|
|
||||||
msr cntv_cval_el0, x4
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* Restore sctlr with the wxn bit cleared. */
|
|
||||||
bic x2, x1, #0x80000
|
|
||||||
msr sctlr_el1, x2
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* Jump to the entrypoint. */
|
|
||||||
br x3
|
|
||||||
|
|
||||||
77: /* Virtual resumption entrypoint. */
|
|
||||||
|
|
||||||
/* Restore sctlr. */
|
|
||||||
msr sctlr_el1, x1
|
|
||||||
dsb sy
|
dsb sy
|
||||||
isb
|
isb
|
||||||
|
|
||||||
ret
|
/* Return. */
|
||||||
|
|
||||||
/* ams::kern::board::nintendo::nx::KSleepManager::InvalidateDataCacheForResumeEntry(uintptr_t level) */
|
|
||||||
.section .sleep._ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm, "ax", %progbits
|
|
||||||
.global _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm
|
|
||||||
.type _ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm, %function
|
|
||||||
_ZN3ams4kern5board8nintendo2nx13KSleepManager33InvalidateDataCacheForResumeEntryEm:
|
|
||||||
/* cpu::DataSynchronizationBarrier(); */
|
|
||||||
dsb sy
|
|
||||||
|
|
||||||
/* const u64 level_sel_value = level << 1; */
|
|
||||||
lsl x8, x0, #1
|
|
||||||
|
|
||||||
/* cpu::SetCsselrEl1(level_sel_value); */
|
|
||||||
msr csselr_el1, x8
|
|
||||||
|
|
||||||
/* cpu::InstructionMemoryBarrier(); */
|
|
||||||
isb
|
|
||||||
|
|
||||||
/* CacheSizeIdAccessor ccsidr_el1; */
|
|
||||||
mrs x13, ccsidr_el1
|
|
||||||
|
|
||||||
/* const int num_ways = ccsidr_el1.GetAssociativity(); */
|
|
||||||
ubfx w10, w13, #3, #0xA
|
|
||||||
|
|
||||||
/* const int line_size = ccsidr_el1.GetLineSize(); */
|
|
||||||
and w11, w13, #7
|
|
||||||
|
|
||||||
/* const int num_sets = ccsidr_el1.GetNumberOfSets(); */
|
|
||||||
ubfx w13, w13, #0xD, #0xF
|
|
||||||
|
|
||||||
/* int way = 0; */
|
|
||||||
mov w9, wzr
|
|
||||||
|
|
||||||
/* const u64 set_shift = static_cast<u64>(line_size + 4); */
|
|
||||||
add w11, w11, #4
|
|
||||||
|
|
||||||
/* const u64 way_shift = static_cast<u64>(__builtin_clz(num_ways)); */
|
|
||||||
clz w12, w10
|
|
||||||
|
|
||||||
|
|
||||||
0: /* do { */
|
|
||||||
/* int set = 0; */
|
|
||||||
mov w14, wzr
|
|
||||||
|
|
||||||
/* const u64 way_value = (static_cast<u64>(way) << way_shift); */
|
|
||||||
lsl w15, w9, w12
|
|
||||||
|
|
||||||
1: /* do { */
|
|
||||||
|
|
||||||
/* const u64 isw_value = (static_cast<u64>(set) << set_shift) | way_value | level_sel_value; */
|
|
||||||
lsl w16, w14, w11
|
|
||||||
orr w16, w16, w15
|
|
||||||
sxtw x16, w16
|
|
||||||
orr x16, x16, x8
|
|
||||||
|
|
||||||
/* __asm__ __volatile__("dc isw, %0" :: "r"(isw_value) : "memory"); */
|
|
||||||
dc isw, x16
|
|
||||||
|
|
||||||
/* while (set <= num_sets); */
|
|
||||||
cmp w13, w14
|
|
||||||
add w14, w14, #1
|
|
||||||
b.ne 1b
|
|
||||||
|
|
||||||
/* while (way <= num_ways); */
|
|
||||||
cmp w9, w10
|
|
||||||
add w9, w9, #1
|
|
||||||
b.ne 0b
|
|
||||||
|
|
||||||
/* cpu::EnsureInstructionConsistency(); */
|
|
||||||
dsb sy
|
|
||||||
isb
|
|
||||||
ret
|
ret
|
||||||
|
|||||||
@@ -361,16 +361,20 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
/* Return (possibly) adjusted size. */
|
/* Return (possibly) adjusted size. */
|
||||||
constexpr size_t ExtraSystemMemoryForAtmosphere = 56_MB;
|
constexpr size_t ExtraSystemMemoryForAtmosphere = 40_MB;
|
||||||
return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
|
return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
|
size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
|
||||||
/* Verify that our minimum is at least as large as Nintendo's. */
|
/* Verify that our minimum is at least as large as Nintendo's. */
|
||||||
constexpr size_t MinimumSize = ::ams::svc::RequiredNonSecureSystemMemorySize;
|
constexpr size_t MinimumSizeWithFatal = ::ams::svc::RequiredNonSecureSystemMemorySizeWithFatal;
|
||||||
static_assert(MinimumSize >= 0x29C8000);
|
static_assert(MinimumSizeWithFatal >= 0x2C04000);
|
||||||
|
|
||||||
return MinimumSize;
|
constexpr size_t MinimumSizeWithoutFatal = ::ams::svc::RequiredNonSecureSystemMemorySize;
|
||||||
|
static_assert(MinimumSizeWithoutFatal >= 0x2A00000);
|
||||||
|
|
||||||
|
/* Include fatal in non-seure size on 16.0.0+. */
|
||||||
|
return kern::GetTargetFirmware() >= ams::TargetFirmware_16_0_0 ? MinimumSizeWithFatal : MinimumSizeWithoutFatal;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 KSystemControl::Init::GetDebugLogUartPort() {
|
u8 KSystemControl::Init::GetDebugLogUartPort() {
|
||||||
@@ -382,7 +386,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
return static_cast<u8>((value >> 32) & 0xFF);
|
return static_cast<u8>((value >> 32) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSystemControl::Init::CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
void KSystemControl::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor, false>(core_id, entrypoint, arg)) == 0);
|
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor, false>(core_id, entrypoint, arg)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,40 +402,41 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
/* System Initialization. */
|
/* System Initialization. */
|
||||||
void KSystemControl::InitializePhase1() {
|
void KSystemControl::InitializePhase1() {
|
||||||
/* Initialize our random generator. */
|
/* Configure KTargetSystem. */
|
||||||
|
{
|
||||||
|
/* Set IsDebugMode. */
|
||||||
|
{
|
||||||
|
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
|
||||||
|
|
||||||
|
/* If debug mode, we want to initialize uart logging. */
|
||||||
|
KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set Kernel Configuration. */
|
||||||
|
{
|
||||||
|
const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
|
||||||
|
|
||||||
|
KTargetSystem::EnableDebugMemoryFill(kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>());
|
||||||
|
KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>());
|
||||||
|
KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>());
|
||||||
|
KTargetSystem::EnableUserPmuAccess(kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>());
|
||||||
|
|
||||||
|
g_call_smc_on_panic = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set Kernel Debugging. */
|
||||||
|
{
|
||||||
|
/* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
|
||||||
|
/* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
|
||||||
|
KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize random and resource limit. */
|
||||||
{
|
{
|
||||||
u64 seed;
|
u64 seed;
|
||||||
smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed));
|
smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed));
|
||||||
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
|
KSystemControlBase::InitializePhase1Base(seed);
|
||||||
s_initialized_random_generator = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set IsDebugMode. */
|
|
||||||
{
|
|
||||||
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
|
|
||||||
|
|
||||||
/* If debug mode, we want to initialize uart logging. */
|
|
||||||
KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode());
|
|
||||||
KDebugLog::Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set Kernel Configuration. */
|
|
||||||
{
|
|
||||||
const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
|
|
||||||
|
|
||||||
KTargetSystem::EnableDebugMemoryFill(kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>());
|
|
||||||
KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>());
|
|
||||||
KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>());
|
|
||||||
KTargetSystem::EnableUserPmuAccess(kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>());
|
|
||||||
|
|
||||||
g_call_smc_on_panic = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set Kernel Debugging. */
|
|
||||||
{
|
|
||||||
/* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
|
|
||||||
/* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
|
|
||||||
KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure the Kernel Carveout region. */
|
/* Configure the Kernel Carveout region. */
|
||||||
@@ -441,9 +446,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize());
|
smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the system resource limit (and potentially other things). */
|
|
||||||
KSystemControlBase::InitializePhase1(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSystemControl::InitializePhase2() {
|
void KSystemControl::InitializePhase2() {
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ namespace ams::kern::board::nintendo::nx::lps {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry) {
|
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg) {
|
||||||
/* Verify that we're allowed to perform suspension. */
|
/* Verify that we're allowed to perform suspension. */
|
||||||
MESOSPHERE_ABORT_UNLESS(g_lps_init_done);
|
MESOSPHERE_ABORT_UNLESS(g_lps_init_done);
|
||||||
MESOSPHERE_ABORT_UNLESS(GetCurrentCoreId() == 0);
|
MESOSPHERE_ABORT_UNLESS(GetCurrentCoreId() == 0);
|
||||||
@@ -416,7 +416,7 @@ namespace ams::kern::board::nintendo::nx::lps {
|
|||||||
Read(g_pmc_address + APBDEV_PMC_SCRATCH0);
|
Read(g_pmc_address + APBDEV_PMC_SCRATCH0);
|
||||||
|
|
||||||
/* Invoke the sleep hander. */
|
/* Invoke the sleep hander. */
|
||||||
KSleepManager::CpuSleepHandler(arg, entry);
|
KSleepManager::CpuSleepHandler(arg, entry, entry_arg);
|
||||||
|
|
||||||
/* Disable deep power down. */
|
/* Disable deep power down. */
|
||||||
Write(g_pmc_address + APBDEV_PMC_DPD_ENABLE, 0);
|
Write(g_pmc_address + APBDEV_PMC_DPD_ENABLE, 0);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
Result EnableSuspend(bool enable);
|
Result EnableSuspend(bool enable);
|
||||||
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry);
|
void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry, uintptr_t entry_arg);
|
||||||
void ResumeBpmpFirmware();
|
void ResumeBpmpFirmware();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace ams::kern::init {
|
|||||||
|
|
||||||
/* For macro convenience. */
|
/* For macro convenience. */
|
||||||
using KSessionRequestMappings = KSessionRequest::SessionMappings::DynamicMappings;
|
using KSessionRequestMappings = KSessionRequest::SessionMappings::DynamicMappings;
|
||||||
|
using KThreadLockInfo = KThread::LockWithPriorityInheritanceInfo;
|
||||||
|
|
||||||
#define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS
|
#define SLAB_COUNT(CLASS) g_slab_resource_counts.num_##CLASS
|
||||||
|
|
||||||
@@ -43,8 +44,9 @@ namespace ams::kern::init {
|
|||||||
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
|
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
|
||||||
HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \
|
HANDLER(KIoPool, (SLAB_COUNT(KIoPool)), ## __VA_ARGS__) \
|
||||||
HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__) \
|
HANDLER(KIoRegion, (SLAB_COUNT(KIoRegion)), ## __VA_ARGS__) \
|
||||||
|
HANDLER(KSessionRequestMappings, (SLAB_COUNT(KSessionRequestMappings)), ## __VA_ARGS__) \
|
||||||
HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
|
HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ## __VA_ARGS__) \
|
||||||
HANDLER(KSessionRequestMappings, (SLAB_COUNT(KSessionRequestMappings)), ## __VA_ARGS__)
|
HANDLER(KThreadLockInfo, (SLAB_COUNT(KThread)), ## __VA_ARGS__)
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -140,7 +142,7 @@ namespace ams::kern::init {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t CalculateSlabHeapGapSize() {
|
size_t CalculateSlabHeapGapSize() {
|
||||||
constexpr size_t KernelSlabHeapGapSize = 2_MB - 320_KB;
|
constexpr size_t KernelSlabHeapGapSize = 2_MB - 356_KB;
|
||||||
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
|
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
|
||||||
return KernelSlabHeapGapSize;
|
return KernelSlabHeapGapSize;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool DecrementIfLessThan(s32 *out, KProcessAddress address, s32 value) {
|
ALWAYS_INLINE bool DecrementIfLessThan(s32 *out, KProcessAddress address, s32 value) {
|
||||||
KScopedInterruptDisable di;
|
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
|
||||||
|
/* KScopedInterruptDisable di; */
|
||||||
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
|
|
||||||
if (!cpu::CanAccessAtomic(address)) {
|
if (!cpu::CanAccessAtomic(address)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -34,7 +36,9 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool UpdateIfEqual(s32 *out, KProcessAddress address, s32 value, s32 new_value) {
|
ALWAYS_INLINE bool UpdateIfEqual(s32 *out, KProcessAddress address, s32 value, s32 new_value) {
|
||||||
KScopedInterruptDisable di;
|
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
|
||||||
|
/* KScopedInterruptDisable di; */
|
||||||
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
|
|
||||||
if (!cpu::CanAccessAtomic(address)) {
|
if (!cpu::CanAccessAtomic(address)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::max();
|
constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::max();
|
||||||
|
|
||||||
constexpr KAddressSpaceInfo AddressSpaceInfos[] = {
|
constinit KAddressSpaceInfo AddressSpaceInfos[] = {
|
||||||
{ 32, ams::svc::AddressSmallMap32Start, ams::svc::AddressSmallMap32Size, KAddressSpaceInfo::Type_MapSmall, },
|
{ 32, ams::svc::AddressSmallMap32Start, ams::svc::AddressSmallMap32Size, KAddressSpaceInfo::Type_MapSmall, },
|
||||||
{ 32, ams::svc::AddressLargeMap32Start, ams::svc::AddressLargeMap32Size, KAddressSpaceInfo::Type_MapLarge, },
|
{ 32, ams::svc::AddressLargeMap32Start, ams::svc::AddressLargeMap32Size, KAddressSpaceInfo::Type_MapLarge, },
|
||||||
{ 32, Invalid, ams::svc::AddressMemoryRegionHeap32Size, KAddressSpaceInfo::Type_Heap, },
|
{ 32, Invalid, ams::svc::AddressMemoryRegionHeap32Size, KAddressSpaceInfo::Type_Heap, },
|
||||||
@@ -37,67 +37,27 @@ namespace ams::kern {
|
|||||||
{ 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, },
|
{ 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, },
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr bool IsAllowedIndexForAddress(size_t index) {
|
KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) {
|
||||||
return index < util::size(AddressSpaceInfos) && AddressSpaceInfos[index].GetAddress() != Invalid;
|
for (auto &info : AddressSpaceInfos) {
|
||||||
}
|
if (info.GetWidth() == width && info.GetType() == type) {
|
||||||
|
return info;
|
||||||
constexpr size_t AddressSpaceIndices32Bit[KAddressSpaceInfo::Type_Count] = {
|
}
|
||||||
0, 1, 0, 2, 0, 3,
|
}
|
||||||
};
|
MESOSPHERE_PANIC("Could not find AddressSpaceInfo");
|
||||||
|
|
||||||
constexpr size_t AddressSpaceIndices36Bit[KAddressSpaceInfo::Type_Count] = {
|
|
||||||
4, 5, 4, 6, 4, 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr size_t AddressSpaceIndices39Bit[KAddressSpaceInfo::Type_Count] = {
|
|
||||||
9, 8, 8, 10, 12, 11,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) {
|
|
||||||
return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Map39Bit && type != KAddressSpaceInfo::Type_Stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) {
|
|
||||||
return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Map39Bit && type != KAddressSpaceInfo::Type_Stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) {
|
|
||||||
return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_MapLarge;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) {
|
uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) {
|
||||||
switch (width) {
|
return GetAddressSpaceInfo(width, type).GetAddress();
|
||||||
case 32:
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed32BitType(type));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[type]));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices32Bit[type]].GetAddress();
|
|
||||||
case 36:
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed36BitType(type));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[type]));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices36Bit[type]].GetAddress();
|
|
||||||
case 39:
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed39BitType(type));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[type]));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices39Bit[type]].GetAddress();
|
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) {
|
size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) {
|
||||||
switch (width) {
|
return GetAddressSpaceInfo(width, type).GetSize();
|
||||||
case 32:
|
}
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed32BitType(type));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices32Bit[type]].GetSize();
|
void KAddressSpaceInfo::SetAddressSpaceSize(size_t width, Type type, size_t size) {
|
||||||
case 36:
|
GetAddressSpaceInfo(width, type).SetSize(size);
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed36BitType(type));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices36Bit[type]].GetSize();
|
|
||||||
case 39:
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsAllowed39BitType(type));
|
|
||||||
return AddressSpaceInfos[AddressSpaceIndices39Bit[type]].GetSize();
|
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,34 +77,35 @@ namespace ams::kern {
|
|||||||
KScopedSchedulerLock sl;
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
/* Remove waiter thread. */
|
/* Remove waiter thread. */
|
||||||
s32 num_waiters;
|
bool has_waiters;
|
||||||
KThread *next_owner_thread = owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
|
KThread * const next_owner_thread = owner_thread->RemoveWaiterByKey(std::addressof(has_waiters), addr);
|
||||||
|
|
||||||
/* Determine the next tag. */
|
/* Determine the next tag. */
|
||||||
u32 next_value = 0;
|
u32 next_value = 0;
|
||||||
if (next_owner_thread != nullptr) {
|
if (next_owner_thread != nullptr) {
|
||||||
next_value = next_owner_thread->GetAddressKeyValue();
|
next_value = next_owner_thread->GetAddressKeyValue();
|
||||||
if (num_waiters > 1) {
|
if (has_waiters) {
|
||||||
next_value |= ams::svc::HandleWaitMask;
|
next_value |= ams::svc::HandleWaitMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the value to userspace. */
|
|
||||||
Result result;
|
|
||||||
if (AMS_LIKELY(WriteToUser(addr, std::addressof(next_value)))) {
|
|
||||||
result = ResultSuccess();
|
|
||||||
} else {
|
|
||||||
result = svc::ResultInvalidCurrentMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Signal the next owner thread. */
|
|
||||||
next_owner_thread->EndWait(result);
|
|
||||||
R_RETURN(result);
|
|
||||||
} else {
|
|
||||||
/* Just write the value to userspace. */
|
|
||||||
R_UNLESS(WriteToUser(addr, std::addressof(next_value)), svc::ResultInvalidCurrentMemory());
|
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Synchronize memory before proceeding. */
|
||||||
|
cpu::DataMemoryBarrierInnerShareable();
|
||||||
|
|
||||||
|
/* Write the value to userspace. */
|
||||||
|
Result result;
|
||||||
|
if (AMS_LIKELY(WriteToUser(addr, std::addressof(next_value)))) {
|
||||||
|
result = ResultSuccess();
|
||||||
|
} else {
|
||||||
|
result = svc::ResultInvalidCurrentMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If necessary, signal the next owner thread. */
|
||||||
|
if (next_owner_thread != nullptr) {
|
||||||
|
next_owner_thread->EndWait(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
R_RETURN(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +158,8 @@ namespace ams::kern {
|
|||||||
u32 prev_tag;
|
u32 prev_tag;
|
||||||
bool can_access;
|
bool can_access;
|
||||||
{
|
{
|
||||||
KScopedInterruptDisable di;
|
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
|
||||||
|
/* KScopedInterruptDisable di; */
|
||||||
|
|
||||||
can_access = cpu::CanAccessAtomic(address);
|
can_access = cpu::CanAccessAtomic(address);
|
||||||
if (AMS_LIKELY(can_access)) {
|
if (AMS_LIKELY(can_access)) {
|
||||||
@@ -198,9 +200,11 @@ namespace ams::kern {
|
|||||||
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetConditionVariableKey() == cv_key)) {
|
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) && (it->GetConditionVariableKey() == cv_key)) {
|
||||||
KThread *target_thread = std::addressof(*it);
|
KThread *target_thread = std::addressof(*it);
|
||||||
|
|
||||||
this->SignalImpl(target_thread);
|
|
||||||
it = m_tree.erase(it);
|
it = m_tree.erase(it);
|
||||||
target_thread->ClearConditionVariable();
|
target_thread->ClearConditionVariable();
|
||||||
|
|
||||||
|
this->SignalImpl(target_thread);
|
||||||
|
|
||||||
++num_waiters;
|
++num_waiters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,15 +234,15 @@ namespace ams::kern {
|
|||||||
/* Update the value and process for the next owner. */
|
/* Update the value and process for the next owner. */
|
||||||
{
|
{
|
||||||
/* Remove waiter thread. */
|
/* Remove waiter thread. */
|
||||||
s32 num_waiters;
|
bool has_waiters;
|
||||||
KThread *next_owner_thread = cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), GetInteger(addr));
|
KThread *next_owner_thread = cur_thread->RemoveWaiterByKey(std::addressof(has_waiters), GetInteger(addr));
|
||||||
|
|
||||||
/* Update for the next owner thread. */
|
/* Update for the next owner thread. */
|
||||||
u32 next_value = 0;
|
u32 next_value = 0;
|
||||||
if (next_owner_thread != nullptr) {
|
if (next_owner_thread != nullptr) {
|
||||||
/* Get the next tag value. */
|
/* Get the next tag value. */
|
||||||
next_value = next_owner_thread->GetAddressKeyValue();
|
next_value = next_owner_thread->GetAddressKeyValue();
|
||||||
if (num_waiters > 1) {
|
if (has_waiters) {
|
||||||
next_value |= ams::svc::HandleWaitMask;
|
next_value |= ams::svc::HandleWaitMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -219,12 +219,21 @@ namespace ams::kern {
|
|||||||
const s32 core_id = GetCurrentCoreId();
|
const s32 core_id = GetCurrentCoreId();
|
||||||
KThread *thread = process->GetRunningThread(core_id);
|
KThread *thread = process->GetRunningThread(core_id);
|
||||||
|
|
||||||
/* Check that the thread's idle count is correct. */
|
/* We want to check that the thread is actually running. */
|
||||||
R_UNLESS(process->GetRunningThreadIdleCount(core_id) == Kernel::GetScheduler(core_id).GetIdleCount(), svc::ResultNoThread());
|
/* If it is, then the scheduler will have just switched from the thread to the current thread. */
|
||||||
|
/* This implies exactly one switch will have taken place, and the current thread will be on the current core. */
|
||||||
/* Check that the thread is running on the current core. */
|
const auto &scheduler = Kernel::GetScheduler(core_id);
|
||||||
R_UNLESS(thread != nullptr, svc::ResultUnknownThread());
|
if (!(thread != nullptr && thread->GetActiveCore() == core_id && process->GetRunningThreadSwitchCount(core_id) + 1 == scheduler.GetSwitchCount())) {
|
||||||
R_UNLESS(thread->GetActiveCore() == core_id, svc::ResultUnknownThread());
|
/* The most recent thread switch was from a thread other than the expected one to the current one. */
|
||||||
|
/* We want to use the appropriate result to inform userland about what thread we switched from. */
|
||||||
|
if (scheduler.GetIdleCount() + 1 == scheduler.GetSwitchCount()) {
|
||||||
|
/* We switched from the idle thread. */
|
||||||
|
R_THROW(svc::ResultNoThread());
|
||||||
|
} else {
|
||||||
|
/* We switched from some other unknown thread. */
|
||||||
|
R_THROW(svc::ResultUnknownThread());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the thread's exception context. */
|
/* Get the thread's exception context. */
|
||||||
GetExceptionContext(thread)->GetSvcThreadContext(out_context);
|
GetExceptionContext(thread)->GetSvcThreadContext(out_context);
|
||||||
@@ -280,7 +289,7 @@ namespace ams::kern {
|
|||||||
m_old_process_state = target->SetDebugObject(this);
|
m_old_process_state = target->SetDebugObject(this);
|
||||||
|
|
||||||
/* Send an event for our attaching to the process. */
|
/* Send an event for our attaching to the process. */
|
||||||
this->PushDebugEvent(ams::svc::DebugEvent_CreateProcess);
|
this->PushDebugEvent(ams::svc::DebugEvent_CreateProcess, nullptr, 0);
|
||||||
|
|
||||||
/* Send events for attaching to each thread in the process. */
|
/* Send events for attaching to each thread in the process. */
|
||||||
{
|
{
|
||||||
@@ -295,7 +304,8 @@ namespace ams::kern {
|
|||||||
it->SetDebugAttached();
|
it->SetDebugAttached();
|
||||||
|
|
||||||
/* Send the event. */
|
/* Send the event. */
|
||||||
this->PushDebugEvent(ams::svc::DebugEvent_CreateThread, it->GetId(), GetInteger(it->GetThreadLocalRegionAddress()));
|
const uintptr_t params[2] = { it->GetId(), GetInteger(it->GetThreadLocalRegionAddress()) };
|
||||||
|
this->PushDebugEvent(ams::svc::DebugEvent_CreateThread, params, util::size(params));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,7 +316,8 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Send an exception event to represent our attaching. */
|
/* Send an exception event to represent our attaching. */
|
||||||
this->PushDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_DebuggerAttached);
|
const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::DebugException_DebuggerAttached) };
|
||||||
|
this->PushDebugEvent(ams::svc::DebugEvent_Exception, params, util::size(params));
|
||||||
|
|
||||||
/* Signal. */
|
/* Signal. */
|
||||||
this->NotifyAvailable();
|
this->NotifyAvailable();
|
||||||
@@ -344,22 +355,22 @@ namespace ams::kern {
|
|||||||
/* Get the currently active threads. */
|
/* Get the currently active threads. */
|
||||||
constexpr u64 ThreadIdNoThread = -1ll;
|
constexpr u64 ThreadIdNoThread = -1ll;
|
||||||
constexpr u64 ThreadIdUnknownThread = -2ll;
|
constexpr u64 ThreadIdUnknownThread = -2ll;
|
||||||
u64 thread_ids[cpu::NumCores];
|
uintptr_t debug_info_params[1 + cpu::NumCores] = { static_cast<uintptr_t>(ams::svc::DebugException_DebuggerBreak), };
|
||||||
for (size_t i = 0; i < util::size(thread_ids); ++i) {
|
for (size_t i = 0; i < cpu::NumCores; ++i) {
|
||||||
/* Get the currently running thread. */
|
/* Get the currently running thread. */
|
||||||
KThread *thread = target->GetRunningThread(i);
|
KThread *thread = target->GetRunningThread(i);
|
||||||
|
|
||||||
/* Check that the thread's idle count is correct. */
|
/* Check that the thread's idle count is correct. */
|
||||||
if (target->GetRunningThreadIdleCount(i) == Kernel::GetScheduler(i).GetIdleCount()) {
|
if (target->GetRunningThreadIdleCount(i) == Kernel::GetScheduler(i).GetIdleCount()) {
|
||||||
if (thread != nullptr && static_cast<size_t>(thread->GetActiveCore()) == i) {
|
if (thread != nullptr && static_cast<size_t>(thread->GetActiveCore()) == i) {
|
||||||
thread_ids[i] = thread->GetId();
|
debug_info_params[1 + i] = thread->GetId();
|
||||||
} else {
|
} else {
|
||||||
/* We found an unknown thread. */
|
/* We found an unknown thread. */
|
||||||
thread_ids[i] = ThreadIdUnknownThread;
|
debug_info_params[1 + i] = ThreadIdUnknownThread;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* We didn't find a thread. */
|
/* We didn't find a thread. */
|
||||||
thread_ids[i] = ThreadIdNoThread;
|
debug_info_params[1 + i] = ThreadIdNoThread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,11 +384,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Send an exception event to represent our breaking the process. */
|
/* Send an exception event to represent our breaking the process. */
|
||||||
/* TODO: How should this be handled in the case of more than 4 physical cores? */
|
this->PushDebugEvent(ams::svc::DebugEvent_Exception, debug_info_params, util::size(debug_info_params));
|
||||||
static_assert(util::size(thread_ids) <= 4);
|
|
||||||
[&]<size_t... Ix>(std::index_sequence<Ix...>) ALWAYS_INLINE_LAMBDA {
|
|
||||||
this->PushDebugEvent(ams::svc::DebugEvent_Exception, ams::svc::DebugException_DebuggerBreak, thread_ids[Ix]...);
|
|
||||||
}(std::make_index_sequence<util::size(thread_ids)>());
|
|
||||||
|
|
||||||
/* Signal. */
|
/* Signal. */
|
||||||
this->NotifyAvailable();
|
this->NotifyAvailable();
|
||||||
@@ -725,7 +732,7 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
KEventInfo *KDebugBase::CreateDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4, u64 cur_thread_id) {
|
KEventInfo *KDebugBase::CreateDebugEvent(ams::svc::DebugEvent event, u64 cur_thread_id, const uintptr_t *params, size_t num_params) {
|
||||||
/* Allocate a new event. */
|
/* Allocate a new event. */
|
||||||
KEventInfo *info = KEventInfo::Allocate();
|
KEventInfo *info = KEventInfo::Allocate();
|
||||||
|
|
||||||
@@ -740,23 +747,33 @@ namespace ams::kern {
|
|||||||
switch (event) {
|
switch (event) {
|
||||||
case ams::svc::DebugEvent_CreateProcess:
|
case ams::svc::DebugEvent_CreateProcess:
|
||||||
{
|
{
|
||||||
/* ... */
|
/* Check parameters. */
|
||||||
|
MESOSPHERE_ASSERT(params == nullptr);
|
||||||
|
MESOSPHERE_ASSERT(num_params == 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugEvent_CreateThread:
|
case ams::svc::DebugEvent_CreateThread:
|
||||||
{
|
{
|
||||||
|
/* Check parameters. */
|
||||||
|
MESOSPHERE_ASSERT(params != nullptr);
|
||||||
|
MESOSPHERE_ASSERT(num_params == 2);
|
||||||
|
|
||||||
/* Set the thread id. */
|
/* Set the thread id. */
|
||||||
info->thread_id = param0;
|
info->thread_id = params[0];
|
||||||
|
|
||||||
/* Set the thread creation info. */
|
/* Set the thread creation info. */
|
||||||
info->info.create_thread.thread_id = param0;
|
info->info.create_thread.thread_id = params[0];
|
||||||
info->info.create_thread.tls_address = param1;
|
info->info.create_thread.tls_address = params[1];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugEvent_ExitProcess:
|
case ams::svc::DebugEvent_ExitProcess:
|
||||||
{
|
{
|
||||||
|
/* Check parameters. */
|
||||||
|
MESOSPHERE_ASSERT(params != nullptr);
|
||||||
|
MESOSPHERE_ASSERT(num_params == 1);
|
||||||
|
|
||||||
/* Set the exit reason. */
|
/* Set the exit reason. */
|
||||||
info->info.exit_process.reason = static_cast<ams::svc::ProcessExitReason>(param0);
|
info->info.exit_process.reason = static_cast<ams::svc::ProcessExitReason>(params[0]);
|
||||||
|
|
||||||
/* Clear the thread id and flags. */
|
/* Clear the thread id and flags. */
|
||||||
info->thread_id = 0;
|
info->thread_id = 0;
|
||||||
@@ -765,30 +782,40 @@ namespace ams::kern {
|
|||||||
break;
|
break;
|
||||||
case ams::svc::DebugEvent_ExitThread:
|
case ams::svc::DebugEvent_ExitThread:
|
||||||
{
|
{
|
||||||
|
/* Check parameters. */
|
||||||
|
MESOSPHERE_ASSERT(params != nullptr);
|
||||||
|
MESOSPHERE_ASSERT(num_params == 2);
|
||||||
|
|
||||||
/* Set the thread id. */
|
/* Set the thread id. */
|
||||||
info->thread_id = param0;
|
info->thread_id = params[0];
|
||||||
|
|
||||||
/* Set the exit reason. */
|
/* Set the exit reason. */
|
||||||
info->info.exit_thread.reason = static_cast<ams::svc::ThreadExitReason>(param1);
|
info->info.exit_thread.reason = static_cast<ams::svc::ThreadExitReason>(params[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugEvent_Exception:
|
case ams::svc::DebugEvent_Exception:
|
||||||
{
|
{
|
||||||
|
/* Check parameters. */
|
||||||
|
MESOSPHERE_ASSERT(params != nullptr);
|
||||||
|
MESOSPHERE_ASSERT(num_params >= 1);
|
||||||
|
|
||||||
/* Set the thread id. */
|
/* Set the thread id. */
|
||||||
info->thread_id = cur_thread_id;
|
info->thread_id = cur_thread_id;
|
||||||
|
|
||||||
/* Set the exception type, and clear the count. */
|
/* Set the exception type, and clear the count. */
|
||||||
info->info.exception.exception_type = static_cast<ams::svc::DebugException>(param0);
|
info->info.exception.exception_type = static_cast<ams::svc::DebugException>(params[0]);
|
||||||
info->info.exception.exception_data_count = 0;
|
info->info.exception.exception_data_count = 0;
|
||||||
switch (static_cast<ams::svc::DebugException>(param0)) {
|
switch (static_cast<ams::svc::DebugException>(params[0])) {
|
||||||
case ams::svc::DebugException_UndefinedInstruction:
|
case ams::svc::DebugException_UndefinedInstruction:
|
||||||
case ams::svc::DebugException_BreakPoint:
|
case ams::svc::DebugException_BreakPoint:
|
||||||
case ams::svc::DebugException_UndefinedSystemCall:
|
case ams::svc::DebugException_UndefinedSystemCall:
|
||||||
{
|
{
|
||||||
info->info.exception.exception_address = param1;
|
MESOSPHERE_ASSERT(num_params >= 3);
|
||||||
|
|
||||||
|
info->info.exception.exception_address = params[1];
|
||||||
|
|
||||||
info->info.exception.exception_data_count = 1;
|
info->info.exception.exception_data_count = 1;
|
||||||
info->info.exception.exception_data[0] = param2;
|
info->info.exception.exception_data[0] = params[2];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_DebuggerAttached:
|
case ams::svc::DebugException_DebuggerAttached:
|
||||||
@@ -800,12 +827,14 @@ namespace ams::kern {
|
|||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_UserBreak:
|
case ams::svc::DebugException_UserBreak:
|
||||||
{
|
{
|
||||||
info->info.exception.exception_address = param1;
|
MESOSPHERE_ASSERT(num_params >= 2);
|
||||||
|
|
||||||
info->info.exception.exception_data_count = 3;
|
info->info.exception.exception_address = params[1];
|
||||||
info->info.exception.exception_data[0] = param2;
|
|
||||||
info->info.exception.exception_data[1] = param3;
|
info->info.exception.exception_data_count = 0;
|
||||||
info->info.exception.exception_data[2] = param4;
|
for (size_t i = 2; i < num_params; ++i) {
|
||||||
|
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_DebuggerBreak:
|
case ams::svc::DebugException_DebuggerBreak:
|
||||||
@@ -814,11 +843,10 @@ namespace ams::kern {
|
|||||||
|
|
||||||
info->info.exception.exception_address = 0;
|
info->info.exception.exception_address = 0;
|
||||||
|
|
||||||
info->info.exception.exception_data_count = 4;
|
info->info.exception.exception_data_count = 0;
|
||||||
info->info.exception.exception_data[0] = param1;
|
for (size_t i = 1; i < num_params; ++i) {
|
||||||
info->info.exception.exception_data[1] = param2;
|
info->info.exception.exception_data[info->info.exception.exception_data_count++] = params[i];
|
||||||
info->info.exception.exception_data[2] = param3;
|
}
|
||||||
info->info.exception.exception_data[3] = param4;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_MemorySystemError:
|
case ams::svc::DebugException_MemorySystemError:
|
||||||
@@ -831,7 +859,9 @@ namespace ams::kern {
|
|||||||
case ams::svc::DebugException_AlignmentFault:
|
case ams::svc::DebugException_AlignmentFault:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
info->info.exception.exception_address = param1;
|
MESOSPHERE_ASSERT(num_params >= 2);
|
||||||
|
|
||||||
|
info->info.exception.exception_address = params[1];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -843,9 +873,9 @@ namespace ams::kern {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KDebugBase::PushDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) {
|
void KDebugBase::PushDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
|
||||||
/* Create and enqueue and event. */
|
/* Create and enqueue and event. */
|
||||||
if (KEventInfo *new_info = CreateDebugEvent(event, param0, param1, param2, param3, param4, GetCurrentThread().GetId()); new_info != nullptr) {
|
if (KEventInfo *new_info = CreateDebugEvent(event, GetCurrentThread().GetId(), params, num_params); new_info != nullptr) {
|
||||||
this->EnqueueDebugEventInfo(new_info);
|
this->EnqueueDebugEventInfo(new_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -952,7 +982,10 @@ namespace ams::kern {
|
|||||||
break;
|
break;
|
||||||
case ams::svc::DebugException_DebuggerBreak:
|
case ams::svc::DebugException_DebuggerBreak:
|
||||||
{
|
{
|
||||||
MESOSPHERE_ASSERT(info->info.exception.exception_data_count == 4);
|
/* TODO: How does this work with non-4 cpu count? */
|
||||||
|
static_assert(cpu::NumCores <= 4);
|
||||||
|
|
||||||
|
MESOSPHERE_ASSERT(info->info.exception.exception_data_count == cpu::NumCores);
|
||||||
out->info.exception.specific.debugger_break.active_thread_ids[0] = info->info.exception.exception_data[0];
|
out->info.exception.specific.debugger_break.active_thread_ids[0] = info->info.exception.exception_data[0];
|
||||||
out->info.exception.specific.debugger_break.active_thread_ids[1] = info->info.exception.exception_data[1];
|
out->info.exception.specific.debugger_break.active_thread_ids[1] = info->info.exception.exception_data[1];
|
||||||
out->info.exception.specific.debugger_break.active_thread_ids[2] = info->info.exception.exception_data[2];
|
out->info.exception.specific.debugger_break.active_thread_ids[2] = info->info.exception.exception_data[2];
|
||||||
@@ -1066,7 +1099,7 @@ namespace ams::kern {
|
|||||||
return !empty || !m_is_attached || this->GetProcessUnsafe()->IsTerminated();
|
return !empty || !m_is_attached || this->GetProcessUnsafe()->IsTerminated();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KDebugBase::ProcessDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) {
|
Result KDebugBase::ProcessDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
|
||||||
/* Get the current process. */
|
/* Get the current process. */
|
||||||
KProcess *process = GetCurrentProcessPointer();
|
KProcess *process = GetCurrentProcessPointer();
|
||||||
|
|
||||||
@@ -1108,7 +1141,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Push the event. */
|
/* Push the event. */
|
||||||
debug->PushDebugEvent(event, param0, param1, param2, param3, param4);
|
debug->PushDebugEvent(event, params, num_params);
|
||||||
debug->NotifyAvailable();
|
debug->NotifyAvailable();
|
||||||
|
|
||||||
/* Set the process as breaked. */
|
/* Set the process as breaked. */
|
||||||
@@ -1144,9 +1177,9 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KDebugBase::OnDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4) {
|
Result KDebugBase::OnDebugEvent(ams::svc::DebugEvent event, const uintptr_t *params, size_t num_params) {
|
||||||
if (KProcess *process = GetCurrentProcessPointer(); process != nullptr && process->IsAttachedToDebugger()) {
|
if (KProcess *process = GetCurrentProcessPointer(); process != nullptr && process->IsAttachedToDebugger()) {
|
||||||
R_RETURN(ProcessDebugEvent(event, param0, param1, param2, param3, param4));
|
R_RETURN(ProcessDebugEvent(event, params, num_params));
|
||||||
}
|
}
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -1161,7 +1194,8 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Push the event. */
|
/* Push the event. */
|
||||||
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
|
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
|
||||||
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, ams::svc::ProcessExitReason_ExitProcess);
|
const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::ProcessExitReason_ExitProcess) };
|
||||||
|
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, params, util::size(params));
|
||||||
debug->NotifyAvailable();
|
debug->NotifyAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1179,7 +1213,8 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Push the event. */
|
/* Push the event. */
|
||||||
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
|
if (KDebugBase *debug = GetDebugObject(process); debug != nullptr) {
|
||||||
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, ams::svc::ProcessExitReason_TerminateProcess);
|
const uintptr_t params[1] = { static_cast<uintptr_t>(ams::svc::ProcessExitReason_TerminateProcess) };
|
||||||
|
debug->PushDebugEvent(ams::svc::DebugEvent_ExitProcess, params, util::size(params));
|
||||||
debug->NotifyAvailable();
|
debug->NotifyAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1193,7 +1228,8 @@ namespace ams::kern {
|
|||||||
/* Check if we're attached to a debugger. */
|
/* Check if we're attached to a debugger. */
|
||||||
if (KProcess *process = thread->GetOwnerProcess(); process != nullptr && process->IsAttachedToDebugger()) {
|
if (KProcess *process = thread->GetOwnerProcess(); process != nullptr && process->IsAttachedToDebugger()) {
|
||||||
/* If we are, submit the event. */
|
/* If we are, submit the event. */
|
||||||
R_TRY(OnDebugEvent(ams::svc::DebugEvent_ExitThread, thread->GetId(), thread->IsTerminationRequested() ? ams::svc::ThreadExitReason_TerminateThread : ams::svc::ThreadExitReason_ExitThread));
|
const uintptr_t params[2] = { thread->GetId(), static_cast<uintptr_t>(thread->IsTerminationRequested() ? ams::svc::ThreadExitReason_TerminateThread : ams::svc::ThreadExitReason_ExitThread) };
|
||||||
|
R_TRY(OnDebugEvent(ams::svc::DebugEvent_ExitThread, params, util::size(params)));
|
||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Check if the address/size falls within any allowable extents. */
|
/* Check if the address/size falls within any allowable extents. */
|
||||||
for (const auto &extents : g_io_region_extents) {
|
for (const auto &extents : g_io_region_extents) {
|
||||||
if (extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) {
|
if (extents.size != 0 && extents.address <= address && address + size - 1 <= extents.address + extents.size - 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,12 +106,23 @@ namespace ams::kern {
|
|||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk(m_lock);
|
||||||
|
|
||||||
/* Check that the desired range isn't already in our pool. */
|
/* Check that the desired range isn't already in our pool. */
|
||||||
for (const auto ®ion : m_io_region_list) {
|
{
|
||||||
R_UNLESS(!region.Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
|
/* Get the lowest region with address >= the new region that's already in our tree. */
|
||||||
|
auto lowest_after = m_io_region_tree.nfind_key(new_region->GetAddress());
|
||||||
|
if (lowest_after != m_io_region_tree.end()) {
|
||||||
|
R_UNLESS(!lowest_after->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is no region with address >= the new region already in our tree, but we also need to check */
|
||||||
|
/* for a region with address < the new region already in our tree. */
|
||||||
|
if (lowest_after != m_io_region_tree.begin()) {
|
||||||
|
auto highest_before = --lowest_after;
|
||||||
|
R_UNLESS(!highest_before->Overlaps(new_region->GetAddress(), new_region->GetSize()), svc::ResultBusy());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the region to our pool. */
|
/* Add the region to our pool. */
|
||||||
m_io_region_list.push_back(*new_region);
|
m_io_region_tree.insert(*new_region);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -122,8 +133,8 @@ namespace ams::kern {
|
|||||||
/* Lock ourselves. */
|
/* Lock ourselves. */
|
||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk(m_lock);
|
||||||
|
|
||||||
/* Remove the region from our list. */
|
/* Remove the region from our tree. */
|
||||||
m_io_region_list.erase(m_io_region_list.iterator_to(*region));
|
m_io_region_tree.erase(m_io_region_tree.iterator_to(*region));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ namespace ams::kern {
|
|||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk(m_lock);
|
||||||
|
|
||||||
/* Unmap ourselves. */
|
/* Unmap ourselves. */
|
||||||
R_TRY(GetCurrentProcess().GetPageTable().UnmapIoRegion(address, m_physical_address, size));
|
R_TRY(GetCurrentProcess().GetPageTable().UnmapIoRegion(address, m_physical_address, size, m_mapping));
|
||||||
|
|
||||||
/* Remove ourselves from the current process. */
|
/* Remove ourselves from the current process. */
|
||||||
GetCurrentProcess().RemoveIoRegion(this);
|
GetCurrentProcess().RemoveIoRegion(this);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Sleep the thread. */
|
/* Sleep the thread. */
|
||||||
{
|
{
|
||||||
KScopedSchedulerLockAndSleep lk(&timer, owner, timeout);
|
KScopedSchedulerLockAndSleep lk(std::addressof(timer), owner, timeout);
|
||||||
|
|
||||||
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
|
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
|
||||||
lk.CancelSleep();
|
lk.CancelSleep();
|
||||||
|
|||||||
@@ -68,13 +68,13 @@ namespace ams::kern {
|
|||||||
KScopedSchedulerLock sl;
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
/* Get the next owner. */
|
/* Get the next owner. */
|
||||||
s32 num_waiters;
|
bool has_waiters;
|
||||||
KThread *next_owner = owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_tag)));
|
KThread *next_owner = owner_thread->RemoveWaiterByKey(std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_tag)));
|
||||||
|
|
||||||
/* Pass the lock to the next owner. */
|
/* Pass the lock to the next owner. */
|
||||||
uintptr_t next_tag = 0;
|
uintptr_t next_tag = 0;
|
||||||
if (next_owner != nullptr) {
|
if (next_owner != nullptr) {
|
||||||
next_tag = reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(num_waiters > 1);
|
next_tag = reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(has_waiters);
|
||||||
|
|
||||||
next_owner->EndWait(ResultSuccess());
|
next_owner->EndWait(ResultSuccess());
|
||||||
|
|
||||||
|
|||||||
@@ -74,8 +74,18 @@ namespace ams::kern {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KPageTableBase::MemoryRange::Open() {
|
||||||
|
/* If the range contains heap pages, open them. */
|
||||||
|
if (this->IsHeap()) {
|
||||||
|
Kernel::GetMemoryManager().Open(this->GetAddress(), this->GetSize() / PageSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void KPageTableBase::MemoryRange::Close() {
|
void KPageTableBase::MemoryRange::Close() {
|
||||||
Kernel::GetMemoryManager().Close(address, size / PageSize);
|
/* If the range contains heap pages, close them. */
|
||||||
|
if (this->IsHeap()) {
|
||||||
|
Kernel::GetMemoryManager().Close(this->GetAddress(), this->GetSize() / PageSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end) {
|
Result KPageTableBase::InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end) {
|
||||||
@@ -1504,16 +1514,13 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Check that the memory is contiguous (modulo the reference count bit). */
|
/* Check that the memory is contiguous (modulo the reference count bit). */
|
||||||
const u32 test_state_mask = state_mask | KMemoryState_FlagReferenceCounted;
|
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))) {
|
const bool is_heap = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, test_state_mask, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr));
|
||||||
|
if (!is_heap) {
|
||||||
R_TRY(this->CheckMemoryStateContiguous(address, size, test_state_mask, state, 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. */
|
/* The memory is contiguous, so set the output range. */
|
||||||
*out = {
|
out->Set(phys_address, size, is_heap);
|
||||||
.address = phys_address,
|
|
||||||
.size = size,
|
|
||||||
};
|
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1600,7 +1607,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Perform mapping operation. */
|
/* Perform mapping operation. */
|
||||||
const KPageProperties properties = { new_perm, false, false, DisableMergeAttribute_None };
|
const KPageProperties properties = { new_perm, false, false, DisableMergeAttribute_None };
|
||||||
const auto operation = was_x ? OperationType_ChangePermissionsAndRefresh : OperationType_ChangePermissions;
|
const auto operation = was_x ? OperationType_ChangePermissionsAndRefreshAndFlush : OperationType_ChangePermissions;
|
||||||
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, operation, false));
|
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, operation, false));
|
||||||
|
|
||||||
/* Update the blocks. */
|
/* Update the blocks. */
|
||||||
@@ -1649,7 +1656,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Perform operation. */
|
/* Perform operation. */
|
||||||
const KPageProperties properties = { old_perm, false, (new_attr & KMemoryAttribute_Uncached) != 0, DisableMergeAttribute_None };
|
const KPageProperties properties = { old_perm, false, (new_attr & KMemoryAttribute_Uncached) != 0, DisableMergeAttribute_None };
|
||||||
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissionsAndRefresh, false));
|
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissionsAndRefreshAndFlush, false));
|
||||||
|
|
||||||
/* Update the blocks. */
|
/* Update the blocks. */
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, old_perm, new_attr, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None);
|
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, old_perm, new_attr, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None);
|
||||||
@@ -2019,15 +2026,22 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size) {
|
Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping) {
|
||||||
const size_t num_pages = size / PageSize;
|
const size_t num_pages = size / PageSize;
|
||||||
|
|
||||||
/* Lock the table. */
|
/* Lock the table. */
|
||||||
KScopedLightLock lk(m_general_lock);
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
/* Validate the memory state. */
|
/* Validate the memory state. */
|
||||||
|
KMemoryState old_state;
|
||||||
|
KMemoryPermission old_perm;
|
||||||
|
KMemoryAttribute old_attr;
|
||||||
size_t num_allocator_blocks;
|
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_Locked));
|
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), 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. */
|
/* Validate that the region being unmapped corresponds to the physical range described. */
|
||||||
{
|
{
|
||||||
@@ -2060,9 +2074,23 @@ namespace ams::kern {
|
|||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
|
/* If the region being unmapped is Memory, synchronize. */
|
||||||
|
if (mapping == ams::svc::MemoryMapping_Memory) {
|
||||||
|
/* Change the region to be uncached. */
|
||||||
|
const KPageProperties properties = { old_perm, false, true, DisableMergeAttribute_None };
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissionsAndRefresh, false));
|
||||||
|
|
||||||
|
/* Temporarily unlock ourselves, so that other operations can occur while we flush the region. */
|
||||||
|
m_general_lock.Unlock();
|
||||||
|
ON_SCOPE_EXIT { m_general_lock.Lock(); };
|
||||||
|
|
||||||
|
/* Flush the region. */
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(GetVoidPointer(dst_address), size));
|
||||||
|
}
|
||||||
|
|
||||||
/* Perform the unmap. */
|
/* Perform the unmap. */
|
||||||
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
||||||
R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
|
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), dst_address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
|
||||||
|
|
||||||
/* Update the blocks. */
|
/* Update the blocks. */
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal);
|
m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal);
|
||||||
@@ -2911,7 +2939,7 @@ namespace ams::kern {
|
|||||||
KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None));
|
KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* We got the range, so open it. */
|
/* We got the range, so open it. */
|
||||||
Kernel::GetMemoryManager().Open(out->address, out->size / PageSize);
|
out->Open();
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -2928,7 +2956,7 @@ namespace ams::kern {
|
|||||||
KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared));
|
KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared));
|
||||||
|
|
||||||
/* We got the range, so open it. */
|
/* We got the range, so open it. */
|
||||||
Kernel::GetMemoryManager().Open(out->address, out->size / PageSize);
|
out->Open();
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@@ -2999,7 +3027,7 @@ namespace ams::kern {
|
|||||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* We got the range, so open it. */
|
/* We got the range, so open it. */
|
||||||
Kernel::GetMemoryManager().Open(out->address, out->size / PageSize);
|
out->Open();
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,7 +198,6 @@ namespace ams::kern {
|
|||||||
/* Set misc fields. */
|
/* Set misc fields. */
|
||||||
m_state = State_Created;
|
m_state = State_Created;
|
||||||
m_main_thread_stack_size = 0;
|
m_main_thread_stack_size = 0;
|
||||||
m_creation_time = KHardwareTimer::GetTick();
|
|
||||||
m_used_kernel_memory_size = 0;
|
m_used_kernel_memory_size = 0;
|
||||||
m_ideal_core_id = 0;
|
m_ideal_core_id = 0;
|
||||||
m_flags = params.flags;
|
m_flags = params.flags;
|
||||||
@@ -209,11 +208,16 @@ namespace ams::kern {
|
|||||||
m_is_application = (params.flags & ams::svc::CreateProcessFlag_IsApplication);
|
m_is_application = (params.flags & ams::svc::CreateProcessFlag_IsApplication);
|
||||||
m_is_jit_debug = false;
|
m_is_jit_debug = false;
|
||||||
|
|
||||||
|
#if defined(MESOSPHERE_ENABLE_PROCESS_CREATION_TIME)
|
||||||
|
m_creation_time = KHardwareTimer::GetTick();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set thread fields. */
|
/* Set thread fields. */
|
||||||
for (size_t i = 0; i < cpu::NumCores; i++) {
|
for (size_t i = 0; i < cpu::NumCores; i++) {
|
||||||
m_running_threads[i] = nullptr;
|
m_running_threads[i] = nullptr;
|
||||||
m_pinned_threads[i] = nullptr;
|
m_pinned_threads[i] = nullptr;
|
||||||
m_running_thread_idle_counts[i] = 0;
|
m_running_thread_idle_counts[i] = 0;
|
||||||
|
m_running_thread_switch_counts[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set max memory based on address space type. */
|
/* Set max memory based on address space type. */
|
||||||
@@ -816,8 +820,8 @@ namespace ams::kern {
|
|||||||
m_exception_thread = nullptr;
|
m_exception_thread = nullptr;
|
||||||
|
|
||||||
/* Remove waiter thread. */
|
/* Remove waiter thread. */
|
||||||
s32 num_waiters;
|
bool has_waiters;
|
||||||
if (KThread *next = thread->RemoveWaiterByKey(std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_exception_thread)) | 1); next != nullptr) {
|
if (KThread *next = thread->RemoveWaiterByKey(std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_exception_thread)) | 1); next != nullptr) {
|
||||||
next->EndWait(ResultSuccess());
|
next->EndWait(ResultSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1241,7 +1245,8 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
|
|
||||||
if (m_is_jit_debug) {
|
if (m_is_jit_debug) {
|
||||||
return KDebugBase::CreateDebugEvent(m_jit_debug_event_type, m_jit_debug_exception_type, m_jit_debug_params[0], m_jit_debug_params[1], m_jit_debug_params[2], m_jit_debug_params[3], m_jit_debug_thread_id);
|
const uintptr_t params[5] = { m_jit_debug_exception_type, m_jit_debug_params[0], m_jit_debug_params[1], m_jit_debug_params[2], m_jit_debug_params[3] };
|
||||||
|
return KDebugBase::CreateDebugEvent(m_jit_debug_event_type, m_jit_debug_thread_id, params, util::size(params));
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,10 +88,12 @@ namespace ams::kern {
|
|||||||
if (m_state.should_count_idle) {
|
if (m_state.should_count_idle) {
|
||||||
if (AMS_LIKELY(highest_thread != nullptr)) {
|
if (AMS_LIKELY(highest_thread != nullptr)) {
|
||||||
if (KProcess *process = highest_thread->GetOwnerProcess(); process != nullptr) {
|
if (KProcess *process = highest_thread->GetOwnerProcess(); process != nullptr) {
|
||||||
process->SetRunningThread(m_core_id, highest_thread, m_state.idle_count);
|
/* Set running thread (and increment switch count). */
|
||||||
|
process->SetRunningThread(m_core_id, highest_thread, m_state.idle_count, ++m_state.switch_count);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_state.idle_count++;
|
/* Set idle count and switch count to switch count + 1. */
|
||||||
|
m_state.idle_count = ++m_state.switch_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +243,7 @@ namespace ams::kern {
|
|||||||
if (AMS_LIKELY(!cur_thread->IsTerminationRequested()) && AMS_LIKELY(cur_thread->GetActiveCore() == m_core_id)) {
|
if (AMS_LIKELY(!cur_thread->IsTerminationRequested()) && AMS_LIKELY(cur_thread->GetActiveCore() == m_core_id)) {
|
||||||
m_state.prev_thread = cur_thread;
|
m_state.prev_thread = cur_thread;
|
||||||
} else {
|
} else {
|
||||||
m_state.prev_thread =nullptr;
|
m_state.prev_thread = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,13 @@
|
|||||||
|
|
||||||
namespace ams::kern {
|
namespace ams::kern {
|
||||||
|
|
||||||
|
namespace init {
|
||||||
|
|
||||||
|
/* TODO: Is this function name architecture specific? */
|
||||||
|
void StartOtherCore(const ams::kern::init::KInitArguments *init_args);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialization. */
|
/* Initialization. */
|
||||||
size_t KSystemControlBase::Init::GetRealMemorySize() {
|
size_t KSystemControlBase::Init::GetRealMemorySize() {
|
||||||
return ams::kern::MainMemorySize;
|
return ams::kern::MainMemorySize;
|
||||||
@@ -68,7 +75,7 @@ namespace ams::kern {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSystemControlBase::Init::CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
void KSystemControlBase::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
||||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<0, false>(core_id, entrypoint, arg)) == 0);
|
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<0, false>(core_id, entrypoint, arg)) == 0);
|
||||||
#else
|
#else
|
||||||
@@ -76,6 +83,22 @@ namespace ams::kern {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KSystemControlBase::Init::TurnOnCpu(u64 core_id, const ams::kern::init::KInitArguments *args) {
|
||||||
|
/* Get entrypoint. */
|
||||||
|
KPhysicalAddress entrypoint = Null<KPhysicalAddress>;
|
||||||
|
while (!cpu::GetPhysicalAddressReadable(std::addressof(entrypoint), reinterpret_cast<uintptr_t>(::ams::kern::init::StartOtherCore), true)) { /* ... */ }
|
||||||
|
|
||||||
|
/* Get arguments. */
|
||||||
|
KPhysicalAddress args_addr = Null<KPhysicalAddress>;
|
||||||
|
while (!cpu::GetPhysicalAddressReadable(std::addressof(args_addr), reinterpret_cast<uintptr_t>(args), true)) { /* ... */ }
|
||||||
|
|
||||||
|
/* Ensure cache is correct for the initial arguments. */
|
||||||
|
cpu::StoreDataCacheForInitArguments(args, sizeof(*args));
|
||||||
|
|
||||||
|
/* Turn on the cpu. */
|
||||||
|
KSystemControl::Init::CpuOnImpl(core_id, GetInteger(entrypoint), GetInteger(args_addr));
|
||||||
|
}
|
||||||
|
|
||||||
/* Randomness for Initialization. */
|
/* Randomness for Initialization. */
|
||||||
void KSystemControlBase::Init::GenerateRandom(u64 *dst, size_t count) {
|
void KSystemControlBase::Init::GenerateRandom(u64 *dst, size_t count) {
|
||||||
if (AMS_UNLIKELY(!s_initialized_random_generator)) {
|
if (AMS_UNLIKELY(!s_initialized_random_generator)) {
|
||||||
@@ -100,23 +123,15 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* System Initialization. */
|
/* System Initialization. */
|
||||||
void KSystemControlBase::InitializePhase1(bool skip_target_system) {
|
void KSystemControlBase::InitializePhase1() {
|
||||||
/* Initialize the rng, if we somehow haven't already. */
|
/* Configure KTargetSystem. */
|
||||||
if (AMS_UNLIKELY(!s_initialized_random_generator)) {
|
{
|
||||||
const u64 seed = KHardwareTimer::GetTick();
|
|
||||||
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
|
|
||||||
s_initialized_random_generator = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure KTargetSystem, if we haven't already by an implementation SystemControl. */
|
|
||||||
if (!skip_target_system) {
|
|
||||||
/* Set IsDebugMode. */
|
/* Set IsDebugMode. */
|
||||||
{
|
{
|
||||||
KTargetSystem::SetIsDebugMode(true);
|
KTargetSystem::SetIsDebugMode(true);
|
||||||
|
|
||||||
/* If debug mode, we want to initialize uart logging. */
|
/* If debug mode, we want to initialize uart logging. */
|
||||||
KTargetSystem::EnableDebugLogging(true);
|
KTargetSystem::EnableDebugLogging(true);
|
||||||
KDebugLog::Initialize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set Kernel Configuration. */
|
/* Set Kernel Configuration. */
|
||||||
@@ -135,6 +150,20 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize random and resource limit. */
|
||||||
|
KSystemControlBase::InitializePhase1Base(KHardwareTimer::GetTick());
|
||||||
|
}
|
||||||
|
|
||||||
|
void KSystemControlBase::InitializePhase1Base(u64 seed) {
|
||||||
|
/* Initialize the rng, if we somehow haven't already. */
|
||||||
|
if (AMS_UNLIKELY(!s_initialized_random_generator)) {
|
||||||
|
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
|
||||||
|
s_initialized_random_generator = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize debug logging. */
|
||||||
|
KDebugLog::Initialize();
|
||||||
|
|
||||||
/* System ResourceLimit initialization. */
|
/* System ResourceLimit initialization. */
|
||||||
{
|
{
|
||||||
/* Construct the resource limit object. */
|
/* Construct the resource limit object. */
|
||||||
@@ -144,6 +173,19 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Set the initial limits. */
|
/* Set the initial limits. */
|
||||||
const auto [total_memory_size, kernel_memory_size] = KMemoryLayout::GetTotalAndKernelMemorySizes();
|
const auto [total_memory_size, kernel_memory_size] = KMemoryLayout::GetTotalAndKernelMemorySizes();
|
||||||
|
|
||||||
|
/* Update 39-bit address space infos. */
|
||||||
|
{
|
||||||
|
/* Heap should be equal to the total memory size, minimum 8 GB, maximum 32 GB. */
|
||||||
|
/* Alias should be equal to 8 * heap size, maximum 128 GB. */
|
||||||
|
const size_t heap_size = std::max(std::min(util::AlignUp(total_memory_size, 1_GB), 32_GB), 8_GB);
|
||||||
|
const size_t alias_size = std::min(heap_size * 8, 128_GB);
|
||||||
|
|
||||||
|
/* Set the address space sizes. */
|
||||||
|
KAddressSpaceInfo::SetAddressSpaceSize(39, KAddressSpaceInfo::Type_Heap, heap_size);
|
||||||
|
KAddressSpaceInfo::SetAddressSpaceSize(39, KAddressSpaceInfo::Type_Alias, alias_size);
|
||||||
|
}
|
||||||
|
|
||||||
const auto &slab_counts = init::GetSlabResourceCounts();
|
const auto &slab_counts = init::GetSlabResourceCounts();
|
||||||
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax, total_memory_size));
|
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax, total_memory_size));
|
||||||
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_ThreadCountMax, slab_counts.num_KThread));
|
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_ThreadCountMax, slab_counts.num_KThread));
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ namespace ams::kern {
|
|||||||
m_light_ipc_data = nullptr;
|
m_light_ipc_data = nullptr;
|
||||||
|
|
||||||
/* We're not waiting for a lock, and we haven't disabled migration. */
|
/* We're not waiting for a lock, and we haven't disabled migration. */
|
||||||
m_lock_owner = nullptr;
|
m_waiting_lock_info = nullptr;
|
||||||
m_num_core_migration_disables = 0;
|
m_num_core_migration_disables = 0;
|
||||||
|
|
||||||
/* We have no waiters, and no closed objects. */
|
/* We have no waiters, and no closed objects. */
|
||||||
@@ -397,25 +397,39 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Release any waiters. */
|
/* Release any waiters. */
|
||||||
{
|
{
|
||||||
MESOSPHERE_ASSERT(m_lock_owner == nullptr);
|
MESOSPHERE_ASSERT(m_waiting_lock_info == nullptr);
|
||||||
KScopedSchedulerLock sl;
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
auto it = m_waiter_list.begin();
|
/* Check that we have no kernel waiters. */
|
||||||
while (it != m_waiter_list.end()) {
|
MESOSPHERE_ABORT_UNLESS(m_num_kernel_waiters == 0);
|
||||||
/* Get the thread. */
|
|
||||||
KThread * const waiter = std::addressof(*it);
|
|
||||||
|
|
||||||
/* The thread shouldn't be a kernel waiter. */
|
auto it = m_held_lock_info_list.begin();
|
||||||
MESOSPHERE_ASSERT(!IsKernelAddressKey(waiter->GetAddressKey()));
|
while (it != m_held_lock_info_list.end()) {
|
||||||
|
/* Get the lock info. */
|
||||||
|
auto * const lock_info = std::addressof(*it);
|
||||||
|
|
||||||
/* Clear the lock owner. */
|
/* The lock shouldn't have a kernel waiter. */
|
||||||
waiter->SetLockOwner(nullptr);
|
MESOSPHERE_ASSERT(!IsKernelAddressKey(lock_info->GetAddressKey()));
|
||||||
|
|
||||||
/* Erase the waiter from our list. */
|
/* Remove all waiters. */
|
||||||
it = m_waiter_list.erase(it);
|
while (lock_info->GetWaiterCount() != 0) {
|
||||||
|
/* Get the front waiter. */
|
||||||
|
KThread * const waiter = lock_info->GetHighestPriorityWaiter();
|
||||||
|
|
||||||
/* Cancel the thread's wait. */
|
/* Remove it from the lock. */
|
||||||
waiter->CancelWait(svc::ResultInvalidState(), true);
|
if (lock_info->RemoveWaiter(waiter)) {
|
||||||
|
MESOSPHERE_ASSERT(lock_info->GetWaiterCount() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cancel the thread's wait. */
|
||||||
|
waiter->CancelWait(svc::ResultInvalidState(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the held lock from our list. */
|
||||||
|
it = m_held_lock_info_list.erase(it);
|
||||||
|
|
||||||
|
/* Free the lock info. */
|
||||||
|
LockWithPriorityInheritanceInfo::Free(lock_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -823,11 +837,8 @@ namespace ams::kern {
|
|||||||
void KThread::IncreaseBasePriority(s32 priority) {
|
void KThread::IncreaseBasePriority(s32 priority) {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
MESOSPHERE_ASSERT(ams::svc::HighestThreadPriority <= priority && priority <= ams::svc::LowestThreadPriority);
|
MESOSPHERE_ASSERT(ams::svc::HighestThreadPriority <= priority && priority <= ams::svc::LowestThreadPriority);
|
||||||
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
/* Set our unpin base priority, if we're pinned. */
|
MESOSPHERE_ASSERT(!this->GetStackParameters().is_pinned);
|
||||||
if (this->GetStackParameters().is_pinned && m_base_priority_on_unpin > priority) {
|
|
||||||
m_base_priority_on_unpin = priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set our base priority. */
|
/* Set our base priority. */
|
||||||
if (m_base_priority > priority) {
|
if (m_base_priority > priority) {
|
||||||
@@ -1044,28 +1055,58 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void KThread::AddWaiterImpl(KThread *thread) {
|
void KThread::AddHeldLock(LockWithPriorityInheritanceInfo *lock_info) {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
|
|
||||||
/* Find the right spot to insert the waiter. */
|
/* Set ourselves as the lock's owner. */
|
||||||
auto it = m_waiter_list.begin();
|
lock_info->SetOwner(this);
|
||||||
while (it != m_waiter_list.end()) {
|
|
||||||
if (it->GetPriority() > thread->GetPriority()) {
|
/* Add the lock to our held list. */
|
||||||
break;
|
m_held_lock_info_list.push_front(*lock_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
KThread::LockWithPriorityInheritanceInfo *KThread::FindHeldLock(KProcessAddress address_key) {
|
||||||
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
|
|
||||||
|
/* Try to find an existing held lock. */
|
||||||
|
for (auto &held_lock : m_held_lock_info_list) {
|
||||||
|
if (held_lock.GetAddressKey() == address_key) {
|
||||||
|
return std::addressof(held_lock);
|
||||||
}
|
}
|
||||||
it++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KThread::AddWaiterImpl(KThread *thread) {
|
||||||
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
|
MESOSPHERE_ASSERT(thread->GetConditionVariableTree() == nullptr);
|
||||||
|
|
||||||
|
/* Get the thread's address key. */
|
||||||
|
const auto address_key = thread->GetAddressKey();
|
||||||
|
|
||||||
/* Keep track of how many kernel waiters we have. */
|
/* Keep track of how many kernel waiters we have. */
|
||||||
if (IsKernelAddressKey(thread->GetAddressKey())) {
|
if (IsKernelAddressKey(address_key)) {
|
||||||
MESOSPHERE_ABORT_UNLESS((m_num_kernel_waiters++) >= 0);
|
MESOSPHERE_ABORT_UNLESS((m_num_kernel_waiters++) >= 0);
|
||||||
KScheduler::SetSchedulerUpdateNeeded();
|
KScheduler::SetSchedulerUpdateNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert the waiter. */
|
/* Get the relevant lock info. */
|
||||||
m_waiter_list.insert(it, *thread);
|
auto *lock_info = this->FindHeldLock(address_key);
|
||||||
thread->SetLockOwner(this);
|
if (lock_info == nullptr) {
|
||||||
|
/* Create a new lock for the address key. */
|
||||||
|
lock_info = LockWithPriorityInheritanceInfo::Create(address_key);
|
||||||
|
|
||||||
|
/* Add the new lock to our list. */
|
||||||
|
this->AddHeldLock(lock_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the thread as waiter to the lock info. */
|
||||||
|
lock_info->AddWaiter(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KThread::RemoveWaiterImpl(KThread *thread) {
|
void KThread::RemoveWaiterImpl(KThread *thread) {
|
||||||
@@ -1078,19 +1119,25 @@ namespace ams::kern {
|
|||||||
KScheduler::SetSchedulerUpdateNeeded();
|
KScheduler::SetSchedulerUpdateNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the info for the lock the thread is waiting on. */
|
||||||
|
auto *lock_info = thread->GetWaitingLockInfo();
|
||||||
|
MESOSPHERE_ASSERT(lock_info->GetOwner() == this);
|
||||||
|
|
||||||
/* Remove the waiter. */
|
/* Remove the waiter. */
|
||||||
m_waiter_list.erase(m_waiter_list.iterator_to(*thread));
|
if (lock_info->RemoveWaiter(thread)) {
|
||||||
thread->SetLockOwner(nullptr);
|
m_held_lock_info_list.erase(m_held_lock_info_list.iterator_to(*lock_info));
|
||||||
|
LockWithPriorityInheritanceInfo::Free(lock_info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KThread::RestorePriority(KThread *thread) {
|
void KThread::RestorePriority(KThread *thread) {
|
||||||
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
|
|
||||||
while (true) {
|
while (thread != nullptr) {
|
||||||
/* We want to inherit priority where possible. */
|
/* We want to inherit priority where possible. */
|
||||||
s32 new_priority = thread->GetBasePriority();
|
s32 new_priority = thread->GetBasePriority();
|
||||||
if (thread->HasWaiters()) {
|
for (const auto &held_lock : thread->m_held_lock_info_list) {
|
||||||
new_priority = std::min(new_priority, thread->m_waiter_list.front().GetPriority());
|
new_priority = std::min(new_priority, held_lock.GetHighestPriorityWaiter()->GetPriority());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the priority we would inherit is not different from ours, don't do anything. */
|
/* If the priority we would inherit is not different from ours, don't do anything. */
|
||||||
@@ -1098,6 +1145,14 @@ namespace ams::kern {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the owner of whatever lock this thread is waiting on. */
|
||||||
|
KThread * const lock_owner = thread->GetLockOwner();
|
||||||
|
|
||||||
|
/* If the thread is waiting on some lock, remove it as a waiter to prevent violating red black tree invariants. */
|
||||||
|
if (lock_owner != nullptr) {
|
||||||
|
lock_owner->RemoveWaiterImpl(thread);
|
||||||
|
}
|
||||||
|
|
||||||
/* Ensure we don't violate condition variable red black tree invariants. */
|
/* Ensure we don't violate condition variable red black tree invariants. */
|
||||||
if (auto *cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
|
if (auto *cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
|
||||||
BeforeUpdatePriority(cv_tree, thread);
|
BeforeUpdatePriority(cv_tree, thread);
|
||||||
@@ -1112,73 +1167,94 @@ namespace ams::kern {
|
|||||||
AfterUpdatePriority(cv_tree, thread);
|
AfterUpdatePriority(cv_tree, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we removed the thread from some lock's waiting list, add it back. */
|
||||||
|
if (lock_owner != nullptr) {
|
||||||
|
lock_owner->AddWaiterImpl(thread);
|
||||||
|
}
|
||||||
|
|
||||||
/* Update the scheduler. */
|
/* Update the scheduler. */
|
||||||
KScheduler::OnThreadPriorityChanged(thread, old_priority);
|
KScheduler::OnThreadPriorityChanged(thread, old_priority);
|
||||||
|
|
||||||
/* Keep the lock owner up to date. */
|
/* Continue inheriting priority. */
|
||||||
KThread *lock_owner = thread->GetLockOwner();
|
|
||||||
if (lock_owner == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the thread in the lock owner's sorted list, and continue inheriting. */
|
|
||||||
lock_owner->RemoveWaiterImpl(thread);
|
|
||||||
lock_owner->AddWaiterImpl(thread);
|
|
||||||
thread = lock_owner;
|
thread = lock_owner;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KThread::AddWaiter(KThread *thread) {
|
void KThread::AddWaiter(KThread *thread) {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
|
||||||
this->AddWaiterImpl(thread);
|
this->AddWaiterImpl(thread);
|
||||||
RestorePriority(this);
|
|
||||||
|
/* If the thread has a higher priority than us, we should inherit. */
|
||||||
|
if (thread->GetPriority() < this->GetPriority()) {
|
||||||
|
RestorePriority(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KThread::RemoveWaiter(KThread *thread) {
|
void KThread::RemoveWaiter(KThread *thread) {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
this->RemoveWaiterImpl(thread);
|
this->RemoveWaiterImpl(thread);
|
||||||
RestorePriority(this);
|
|
||||||
|
/* If our priority is the same as the thread's (and we've inherited), we may need to restore to lower priority. */
|
||||||
|
if (this->GetPriority() == thread->GetPriority() && this->GetPriority() < this->GetBasePriority()) {
|
||||||
|
RestorePriority(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KThread *KThread::RemoveWaiterByKey(s32 *out_num_waiters, KProcessAddress key) {
|
KThread *KThread::RemoveWaiterByKey(bool *out_has_waiters, KProcessAddress key) {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread());
|
||||||
|
|
||||||
s32 num_waiters = 0;
|
/* Get the relevant lock info. */
|
||||||
KThread *next_lock_owner = nullptr;
|
auto *lock_info = this->FindHeldLock(key);
|
||||||
auto it = m_waiter_list.begin();
|
if (lock_info == nullptr) {
|
||||||
while (it != m_waiter_list.end()) {
|
*out_has_waiters = false;
|
||||||
if (it->GetAddressKey() == key) {
|
return nullptr;
|
||||||
KThread *thread = std::addressof(*it);
|
}
|
||||||
|
|
||||||
/* Keep track of how many kernel waiters we have. */
|
/* Remove the lock info from our held list. */
|
||||||
if (IsKernelAddressKey(thread->GetAddressKey())) {
|
m_held_lock_info_list.erase(m_held_lock_info_list.iterator_to(*lock_info));
|
||||||
MESOSPHERE_ABORT_UNLESS((m_num_kernel_waiters--) > 0);
|
|
||||||
KScheduler::SetSchedulerUpdateNeeded();
|
|
||||||
}
|
|
||||||
it = m_waiter_list.erase(it);
|
|
||||||
|
|
||||||
/* Update the next lock owner. */
|
/* Keep track of how many kernel waiters we have. */
|
||||||
if (next_lock_owner == nullptr) {
|
if (IsKernelAddressKey(lock_info->GetAddressKey())) {
|
||||||
next_lock_owner = thread;
|
m_num_kernel_waiters -= lock_info->GetWaiterCount();
|
||||||
next_lock_owner->SetLockOwner(nullptr);
|
MESOSPHERE_ABORT_UNLESS(m_num_kernel_waiters >= 0);
|
||||||
} else {
|
KScheduler::SetSchedulerUpdateNeeded();
|
||||||
next_lock_owner->AddWaiterImpl(thread);
|
}
|
||||||
}
|
|
||||||
num_waiters++;
|
MESOSPHERE_ASSERT(lock_info->GetWaiterCount() > 0);
|
||||||
} else {
|
|
||||||
it++;
|
/* Remove the highest priority waiter from the lock to be the next owner. */
|
||||||
|
KThread *next_lock_owner = lock_info->GetHighestPriorityWaiter();
|
||||||
|
if (lock_info->RemoveWaiter(next_lock_owner)) {
|
||||||
|
/* The new owner was the only waiter. */
|
||||||
|
*out_has_waiters = false;
|
||||||
|
|
||||||
|
/* Free the lock info, since it has no waiters. */
|
||||||
|
LockWithPriorityInheritanceInfo::Free(lock_info);
|
||||||
|
} else {
|
||||||
|
/* There are additional waiters on the lock. */
|
||||||
|
*out_has_waiters = true;
|
||||||
|
|
||||||
|
/* Add the lock to the new owner's held list. */
|
||||||
|
next_lock_owner->AddHeldLock(lock_info);
|
||||||
|
|
||||||
|
/* Keep track of any kernel waiters for the new owner. */
|
||||||
|
if (IsKernelAddressKey(lock_info->GetAddressKey())) {
|
||||||
|
next_lock_owner->m_num_kernel_waiters += lock_info->GetWaiterCount();
|
||||||
|
MESOSPHERE_ABORT_UNLESS(next_lock_owner->m_num_kernel_waiters > 0);
|
||||||
|
|
||||||
|
/* NOTE: No need to set scheduler update needed, because we will have already done so when removing earlier. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do priority updates, if we have a next owner. */
|
/* If our priority is the same as the next owner's (and we've inherited), we may need to restore to lower priority. */
|
||||||
if (next_lock_owner) {
|
if (this->GetPriority() == next_lock_owner->GetPriority() && this->GetPriority() < this->GetBasePriority()) {
|
||||||
RestorePriority(this);
|
RestorePriority(this);
|
||||||
RestorePriority(next_lock_owner);
|
/* NOTE: No need to restore priority on the next lock owner, because it was already the highest priority waiter on the lock. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return output. */
|
/* Return the next lock owner. */
|
||||||
*out_num_waiters = num_waiters;
|
|
||||||
return next_lock_owner;
|
return next_lock_owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1309,9 +1385,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Change the thread's priority to be higher than any system thread's. */
|
/* Change the thread's priority to be higher than any system thread's. */
|
||||||
if (this->GetBasePriority() >= ams::svc::SystemThreadPriorityHighest) {
|
this->IncreaseBasePriority(TerminatingThreadPriority);
|
||||||
this->SetBasePriority(TerminatingThreadPriority);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the thread is runnable, send a termination interrupt to other cores. */
|
/* If the thread is runnable, send a termination interrupt to other cores. */
|
||||||
if (this->GetState() == ThreadState_Runnable) {
|
if (this->GetState() == ThreadState_Runnable) {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace ams::kern::svc {
|
|||||||
/* Check whether the address is aligned. */
|
/* Check whether the address is aligned. */
|
||||||
const bool aligned = util::IsAligned(phys_addr, PageSize);
|
const bool aligned = util::IsAligned(phys_addr, PageSize);
|
||||||
|
|
||||||
auto QueryIoMappingFromPageTable = [&](uint64_t phys_addr, size_t size) ALWAYS_INLINE_LAMBDA -> Result {
|
auto QueryMappingFromPageTable = [&](uint64_t phys_addr, size_t size) ALWAYS_INLINE_LAMBDA -> Result {
|
||||||
/* The size must be non-zero. */
|
/* The size must be non-zero. */
|
||||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||||
|
|
||||||
@@ -56,7 +56,12 @@ namespace ams::kern::svc {
|
|||||||
R_UNLESS((phys_addr < phys_addr + size), svc::ResultNotFound());
|
R_UNLESS((phys_addr < phys_addr + size), svc::ResultNotFound());
|
||||||
|
|
||||||
/* Query the mapping. */
|
/* Query the mapping. */
|
||||||
R_TRY(pt.QueryIoMapping(std::addressof(found_address), phys_addr, size));
|
R_TRY_CATCH(pt.QueryIoMapping(std::addressof(found_address), phys_addr, size)) {
|
||||||
|
R_CATCH(svc::ResultNotFound) {
|
||||||
|
/* If we failed to find an io mapping, check if the address is a static mapping. */
|
||||||
|
R_TRY(pt.QueryStaticMapping(std::addressof(found_address), phys_addr, size));
|
||||||
|
}
|
||||||
|
} R_END_TRY_CATCH;
|
||||||
|
|
||||||
/* Use the size as the found size. */
|
/* Use the size as the found size. */
|
||||||
found_size = size;
|
found_size = size;
|
||||||
@@ -66,12 +71,12 @@ namespace ams::kern::svc {
|
|||||||
|
|
||||||
if (aligned) {
|
if (aligned) {
|
||||||
/* Query the input. */
|
/* Query the input. */
|
||||||
R_TRY(QueryIoMappingFromPageTable(phys_addr, size));
|
R_TRY(QueryMappingFromPageTable(phys_addr, size));
|
||||||
} else {
|
} else {
|
||||||
if (kern::GetTargetFirmware() < TargetFirmware_8_0_0 && phys_addr >= PageSize) {
|
if (kern::GetTargetFirmware() < TargetFirmware_8_0_0 && phys_addr >= PageSize) {
|
||||||
/* Query the aligned-down page. */
|
/* Query the aligned-down page. */
|
||||||
const size_t offset = phys_addr & (PageSize - 1);
|
const size_t offset = phys_addr & (PageSize - 1);
|
||||||
R_TRY(QueryIoMappingFromPageTable(phys_addr - offset, size + offset));
|
R_TRY(QueryMappingFromPageTable(phys_addr - offset, size + offset));
|
||||||
|
|
||||||
/* Adjust the output address. */
|
/* Adjust the output address. */
|
||||||
found_address += offset;
|
found_address += offset;
|
||||||
|
|||||||
@@ -36,15 +36,15 @@ namespace ams::kern::svc {
|
|||||||
size_t remaining = size;
|
size_t remaining = size;
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
/* Get a contiguous range to operate on. */
|
/* Get a contiguous range to operate on. */
|
||||||
KPageTableBase::MemoryRange contig_range = { .address = Null<KPhysicalAddress>, .size = 0 };
|
KPageTableBase::MemoryRange contig_range;
|
||||||
R_TRY(page_table.OpenMemoryRangeForProcessCacheOperation(std::addressof(contig_range), cur_address, aligned_end - cur_address));
|
R_TRY(page_table.OpenMemoryRangeForProcessCacheOperation(std::addressof(contig_range), cur_address, aligned_end - cur_address));
|
||||||
|
|
||||||
/* Close the range when we're done operating on it. */
|
/* Close the range when we're done operating on it. */
|
||||||
ON_SCOPE_EXIT { contig_range.Close(); };
|
ON_SCOPE_EXIT { contig_range.Close(); };
|
||||||
|
|
||||||
/* Adjust to remain within range. */
|
/* Adjust to remain within range. */
|
||||||
KVirtualAddress operate_address = KMemoryLayout::GetLinearVirtualAddress(contig_range.address);
|
KVirtualAddress operate_address = KMemoryLayout::GetLinearVirtualAddress(contig_range.GetAddress());
|
||||||
size_t operate_size = contig_range.size;
|
size_t operate_size = contig_range.GetSize();
|
||||||
if (cur_address < address) {
|
if (cur_address < address) {
|
||||||
operate_address += (address - cur_address);
|
operate_address += (address - cur_address);
|
||||||
operate_size -= (address - cur_address);
|
operate_size -= (address - cur_address);
|
||||||
@@ -57,7 +57,7 @@ namespace ams::kern::svc {
|
|||||||
operation.Operate(GetVoidPointer(operate_address), operate_size);
|
operation.Operate(GetVoidPointer(operate_address), operate_size);
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
cur_address += contig_range.size;
|
cur_address += contig_range.GetSize();
|
||||||
remaining -= operate_size;
|
remaining -= operate_size;
|
||||||
}
|
}
|
||||||
MESOSPHERE_ASSERT(remaining == 0);
|
MESOSPHERE_ASSERT(remaining == 0);
|
||||||
|
|||||||
@@ -297,6 +297,19 @@ namespace ams::kern::svc {
|
|||||||
*out = GetCurrentProcess().IsPermittedSvc(static_cast<svc::SvcId>(info_subtype));
|
*out = GetCurrentProcess().IsPermittedSvc(static_cast<svc::SvcId>(info_subtype));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ams::svc::InfoType_IoRegionHint:
|
||||||
|
{
|
||||||
|
/* Verify the sub-type is valid. */
|
||||||
|
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());
|
||||||
|
|
||||||
|
/* Get the io region from its handle. */
|
||||||
|
KScopedAutoObject io_region = GetCurrentProcess().GetHandleTable().GetObject<KIoRegion>(handle);
|
||||||
|
R_UNLESS(io_region.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
|
/* Get the io region's address hint. */
|
||||||
|
*out = io_region->GetHint();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ams::svc::InfoType_MesosphereMeta:
|
case ams::svc::InfoType_MesosphereMeta:
|
||||||
{
|
{
|
||||||
/* Verify the handle is invalid. */
|
/* Verify the handle is invalid. */
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace ams::kern::svc {
|
|||||||
R_UNLESS(size < ams::kern::MainMemorySizeMax, svc::ResultInvalidSize());
|
R_UNLESS(size < ams::kern::MainMemorySizeMax, svc::ResultInvalidSize());
|
||||||
|
|
||||||
/* Set the heap size. */
|
/* Set the heap size. */
|
||||||
KProcessAddress address;
|
KProcessAddress address = Null<KProcessAddress>;
|
||||||
R_TRY(GetCurrentProcess().GetPageTable().SetHeapSize(std::addressof(address), size));
|
R_TRY(GetCurrentProcess().GetPageTable().SetHeapSize(std::addressof(address), size));
|
||||||
|
|
||||||
/* Set the output. */
|
/* Set the output. */
|
||||||
|
|||||||
@@ -174,6 +174,10 @@
|
|||||||
HANDLER(ServiceProfileInfo, 133) \
|
HANDLER(ServiceProfileInfo, 133) \
|
||||||
HANDLER(BluetoothAudioInfo, 134) \
|
HANDLER(BluetoothAudioInfo, 134) \
|
||||||
HANDLER(BluetoothPairingCountInfo, 135) \
|
HANDLER(BluetoothPairingCountInfo, 135) \
|
||||||
|
HANDLER(FsProxyErrorInfo2, 136) \
|
||||||
|
HANDLER(BuiltInWirelessOUIInfo, 137) \
|
||||||
|
HANDLER(WirelessAPOUIInfo, 138) \
|
||||||
|
HANDLER(EthernetAdapterOUIInfo, 139) \
|
||||||
|
|
||||||
#define AMS_ERPT_FOREACH_FIELD(HANDLER) \
|
#define AMS_ERPT_FOREACH_FIELD(HANDLER) \
|
||||||
HANDLER(TestU64, 0, Test, FieldType_NumericU64, FieldFlag_None ) \
|
HANDLER(TestU64, 0, Test, FieldType_NumericU64, FieldFlag_None ) \
|
||||||
@@ -840,4 +844,10 @@
|
|||||||
HANDLER(FatFsBisUserUniqueDirectoryEntryPeakOpenCount, 661, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
HANDLER(FatFsBisUserUniqueDirectoryEntryPeakOpenCount, 661, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||||
HANDLER(FatFsSdCardUniqueFileEntryPeakOpenCount, 662, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
HANDLER(FatFsSdCardUniqueFileEntryPeakOpenCount, 662, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||||
HANDLER(FatFsSdCardUniqueDirectoryEntryPeakOpenCount, 663, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
HANDLER(FatFsSdCardUniqueDirectoryEntryPeakOpenCount, 663, FsProxyErrorInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||||
|
HANDLER(ServerErrorIsRetryable, 664, ErrorInfo, FieldType_Bool, FieldFlag_None ) \
|
||||||
|
HANDLER(FsDeepRetryStartCount, 665, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
|
HANDLER(FsUnrecoverableByGameCardAccessFailedCount, 666, FsProxyErrorInfo2, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
|
HANDLER(BuiltInWirelessOUI, 667, BuiltInWirelessOUIInfo, FieldType_String, FieldFlag_None ) \
|
||||||
|
HANDLER(WirelessAPOUI, 668, WirelessAPOUIInfo, FieldType_String, FieldFlag_None ) \
|
||||||
|
HANDLER(EthernetAdapterOUI, 669, EthernetAdapterOUIInfo, FieldType_String, FieldFlag_None ) \
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ namespace ams::fs {
|
|||||||
SystemProperEncryption = 32,
|
SystemProperEncryption = 32,
|
||||||
SystemProperPartition = 33,
|
SystemProperPartition = 33,
|
||||||
SignedSystemPartitionOnSafeMode = 34,
|
SignedSystemPartitionOnSafeMode = 34,
|
||||||
|
DeviceTreeBlob = 35,
|
||||||
|
System0 = 36,
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *GetBisMountName(BisPartitionId id);
|
const char *GetBisMountName(BisPartitionId id);
|
||||||
|
|||||||
@@ -20,10 +20,10 @@
|
|||||||
|
|
||||||
namespace ams::fs {
|
namespace ams::fs {
|
||||||
|
|
||||||
/* ACCURATE_TO_VERSION: 13.4.0.0 */
|
/* ACCURATE_TO_VERSION: 16.2.0.0 */
|
||||||
Result MountCode(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id);
|
Result MountCode(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id);
|
||||||
|
|
||||||
Result MountCodeForAtmosphereWithRedirection(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific);
|
Result MountCodeForAtmosphereWithRedirection(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, bool is_hbl, bool is_specific);
|
||||||
Result MountCodeForAtmosphere(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id);
|
Result MountCodeForAtmosphere(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ namespace ams::fs {
|
|||||||
ContentType_Data = 4,
|
ContentType_Data = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
Result MountContent(const char *name, const char *path, ContentType content_type);
|
Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ContentType content_type);
|
||||||
Result MountContent(const char *name, const char *path, ncm::ProgramId id, ContentType content_type);
|
Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId id, ContentType content_type);
|
||||||
Result MountContent(const char *name, const char *path, ncm::DataId id, ContentType content_type);
|
Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ncm::DataId id, ContentType content_type);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ namespace ams::fs {
|
|||||||
|
|
||||||
/* ACCURATE_TO_VERSION: Unknown */
|
/* ACCURATE_TO_VERSION: Unknown */
|
||||||
enum ContentAttributes : u8 {
|
enum ContentAttributes : u8 {
|
||||||
ContentAttributes_None = 0,
|
ContentAttributes_None = 0x0,
|
||||||
|
ContentAttributes_All = 0xF,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,16 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere/fs/fs_common.hpp>
|
#include <stratosphere/fs/fs_common.hpp>
|
||||||
|
#include <stratosphere/fs/fs_content_storage_id.hpp>
|
||||||
|
|
||||||
namespace ams::fs {
|
namespace ams::fs {
|
||||||
|
|
||||||
/* ACCURATE_TO_VERSION: Unknown */
|
|
||||||
enum class ContentStorageId : u32 {
|
|
||||||
System = 0,
|
|
||||||
User = 1,
|
|
||||||
SdCard = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr inline const char * const ContentStorageDirectoryName = "Contents";
|
constexpr inline const char * const ContentStorageDirectoryName = "Contents";
|
||||||
|
|
||||||
const char *GetContentStorageMountName(ContentStorageId id);
|
const char *GetContentStorageMountName(ContentStorageId id);
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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 <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::fs {
|
||||||
|
|
||||||
|
/* ACCURATE_TO_VERSION: 16.2.0.0 */
|
||||||
|
enum class ContentStorageId : u32 {
|
||||||
|
System = 0,
|
||||||
|
User = 1,
|
||||||
|
SdCard = 2,
|
||||||
|
System0 = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vapours.hpp>
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/fs/fs_content_attributes.hpp>
|
||||||
|
|
||||||
namespace ams::fs {
|
namespace ams::fs {
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ namespace ams::fs {
|
|||||||
constexpr inline RightsId InvalidRightsId = {};
|
constexpr inline RightsId InvalidRightsId = {};
|
||||||
|
|
||||||
/* Rights ID API */
|
/* Rights ID API */
|
||||||
Result GetRightsId(RightsId *out, const char *path);
|
Result GetRightsId(RightsId *out, const char *path, fs::ContentAttributes attr);
|
||||||
Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path);
|
Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path, fs::ContentAttributes attr);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -50,8 +50,9 @@ namespace ams::fssrv {
|
|||||||
Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid);
|
Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid);
|
||||||
Result OpenDataFileSystemByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out);
|
Result OpenDataFileSystemByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out);
|
||||||
Result OpenFileSystemWithPatch(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type);
|
Result OpenFileSystemWithPatch(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type);
|
||||||
Result OpenFileSystemWithId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type);
|
Result OpenFileSystemWithIdObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type);
|
||||||
Result OpenDataFileSystemByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id);
|
Result OpenDataFileSystemByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id);
|
||||||
|
Result OpenFileSystemWithId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u64 program_id, u32 type);
|
||||||
Result OpenBisFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id);
|
Result OpenBisFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id);
|
||||||
Result OpenBisStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id);
|
Result OpenBisStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id);
|
||||||
Result InvalidateBisCache();
|
Result InvalidateBisCache();
|
||||||
@@ -90,7 +91,8 @@ namespace ams::fssrv {
|
|||||||
Result OpenPatchDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out);
|
Result OpenPatchDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out);
|
||||||
Result OpenDataFileSystemWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index);
|
Result OpenDataFileSystemWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index);
|
||||||
Result OpenDataStorageWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index);
|
Result OpenDataStorageWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index);
|
||||||
Result OpenDataStorageByPath(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type);
|
Result OpenDataStorageByPathObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type);
|
||||||
|
Result OpenDataStorageByPath(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u32 type);
|
||||||
Result OpenDeviceOperator(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out);
|
Result OpenDeviceOperator(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out);
|
||||||
Result OpenSdCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out);
|
Result OpenSdCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out);
|
||||||
Result OpenGameCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out);
|
Result OpenGameCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out);
|
||||||
@@ -103,7 +105,8 @@ namespace ams::fssrv {
|
|||||||
Result RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key);
|
Result RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key);
|
||||||
Result UnregisterAllExternalKey();
|
Result UnregisterAllExternalKey();
|
||||||
Result GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path);
|
Result GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path);
|
||||||
Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path);
|
Result GetRightsIdAndKeyGenerationByPathObsolete(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path);
|
||||||
|
Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr);
|
||||||
Result SetCurrentPosixTimeWithTimeDifference(s64 posix_time, s32 time_difference);
|
Result SetCurrentPosixTimeWithTimeDifference(s64 posix_time, s32 time_difference);
|
||||||
Result GetFreeSpaceSizeForSaveData(ams::sf::Out<s64> out, u8 space_id);
|
Result GetFreeSpaceSizeForSaveData(ams::sf::Out<s64> out, u8 space_id);
|
||||||
Result VerifySaveDataFileSystemBySaveDataSpaceId();
|
Result VerifySaveDataFileSystemBySaveDataSpaceId();
|
||||||
@@ -142,7 +145,8 @@ namespace ams::fssrv {
|
|||||||
public:
|
public:
|
||||||
/* fsp-ldr */
|
/* fsp-ldr */
|
||||||
Result OpenCodeFileSystemDeprecated(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id);
|
Result OpenCodeFileSystemDeprecated(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id);
|
||||||
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id);
|
Result OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id);
|
||||||
|
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id);
|
||||||
Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id);
|
Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id);
|
||||||
};
|
};
|
||||||
static_assert(sf::IsIFileSystemProxy<FileSystemProxyImpl>);
|
static_assert(sf::IsIFileSystemProxy<FileSystemProxyImpl>);
|
||||||
@@ -156,11 +160,16 @@ namespace ams::fssrv {
|
|||||||
R_THROW(fs::ResultPortAcceptableCountLimited());
|
R_THROW(fs::ResultPortAcceptableCountLimited());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id) {
|
Result OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id) {
|
||||||
AMS_UNUSED(out_fs, out_verif, path, program_id);
|
AMS_UNUSED(out_fs, out_verif, path, program_id);
|
||||||
R_THROW(fs::ResultPortAcceptableCountLimited());
|
R_THROW(fs::ResultPortAcceptableCountLimited());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
|
||||||
|
AMS_UNUSED(out_fs, out_verif, path, attr, program_id);
|
||||||
|
R_THROW(fs::ResultPortAcceptableCountLimited());
|
||||||
|
}
|
||||||
|
|
||||||
Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id) {
|
Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id) {
|
||||||
AMS_UNUSED(out, process_id);
|
AMS_UNUSED(out, process_id);
|
||||||
R_THROW(fs::ResultPortAcceptableCountLimited());
|
R_THROW(fs::ResultPortAcceptableCountLimited());
|
||||||
|
|||||||
@@ -27,8 +27,9 @@
|
|||||||
AMS_SF_METHOD_INFO(C, H, 1, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid)) \
|
AMS_SF_METHOD_INFO(C, H, 1, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 2, Result, OpenDataFileSystemByCurrentProcess, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out), (out)) \
|
AMS_SF_METHOD_INFO(C, H, 2, Result, OpenDataFileSystemByCurrentProcess, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out), (out)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 7, Result, OpenFileSystemWithPatch, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type), (out, program_id, type), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 7, Result, OpenFileSystemWithPatch, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type), (out, program_id, type), hos::Version_2_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type), (out, path, program_id, type), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithIdObsolete, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type), (out, path, program_id, type), hos::Version_2_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 9, Result, OpenDataFileSystemByProgramId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id), (out, program_id), hos::Version_3_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 9, Result, OpenDataFileSystemByProgramId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id), (out, program_id), hos::Version_3_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 8, Result, OpenFileSystemWithId, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u64 program_id, u32 type), (out, path, attr, program_id, type), hos::Version_16_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 11, Result, OpenBisFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id), (out, path, id)) \
|
AMS_SF_METHOD_INFO(C, H, 11, Result, OpenBisFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id), (out, path, id)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 12, Result, OpenBisStorage, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id), (out, id)) \
|
AMS_SF_METHOD_INFO(C, H, 12, Result, OpenBisStorage, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id), (out, id)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 13, Result, InvalidateBisCache, (), ()) \
|
AMS_SF_METHOD_INFO(C, H, 13, Result, InvalidateBisCache, (), ()) \
|
||||||
@@ -87,7 +88,8 @@
|
|||||||
AMS_SF_METHOD_INFO(C, H, 203, Result, OpenPatchDataStorageByCurrentProcess, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out), (out)) \
|
AMS_SF_METHOD_INFO(C, H, 203, Result, OpenPatchDataStorageByCurrentProcess, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out), (out)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 204, Result, OpenDataFileSystemWithProgramIndex, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index), (out, index), hos::Version_7_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 204, Result, OpenDataFileSystemWithProgramIndex, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index), (out, index), hos::Version_7_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 205, Result, OpenDataStorageWithProgramIndex, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index), (out, index), hos::Version_7_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 205, Result, OpenDataStorageWithProgramIndex, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index), (out, index), hos::Version_7_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPath, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type), (out, path, type), hos::Version_13_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPathObsolete, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type), (out, path, type), hos::Version_13_0_0, hos::Version_15_0_1) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 206, Result, OpenDataStorageByPath, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u32 type), (out, path, attr, type), hos::Version_16_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 400, Result, OpenDeviceOperator, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out), (out)) \
|
AMS_SF_METHOD_INFO(C, H, 400, Result, OpenDeviceOperator, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out), (out)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 500, Result, OpenSdCardDetectionEventNotifier, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out), (out)) \
|
AMS_SF_METHOD_INFO(C, H, 500, Result, OpenSdCardDetectionEventNotifier, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out), (out)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 501, Result, OpenGameCardDetectionEventNotifier, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out), (out)) \
|
AMS_SF_METHOD_INFO(C, H, 501, Result, OpenGameCardDetectionEventNotifier, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out), (out)) \
|
||||||
@@ -103,8 +105,9 @@
|
|||||||
AMS_SF_METHOD_INFO(C, H, 606, Result, GetRightsId, (ams::sf::Out<fs::RightsId> out, ncm::ProgramId program_id, ncm::StorageId storage_id), (out, program_id, storage_id), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 606, Result, GetRightsId, (ams::sf::Out<fs::RightsId> out, ncm::ProgramId program_id, ncm::StorageId storage_id), (out, program_id, storage_id), hos::Version_2_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 607, Result, RegisterExternalKey, (const fs::RightsId &rights_id, const spl::AccessKey &access_key), (rights_id, access_key), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 607, Result, RegisterExternalKey, (const fs::RightsId &rights_id, const spl::AccessKey &access_key), (rights_id, access_key), hos::Version_2_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 608, Result, UnregisterAllExternalKey, (), (), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 608, Result, UnregisterAllExternalKey, (), (), hos::Version_2_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 609, Result, GetRightsIdByPath, (ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path), (out, path), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 609, Result, GetRightsIdByPath, (ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path), (out, path), hos::Version_2_0_0, hos::Version_15_0_1) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 610, Result, GetRightsIdAndKeyGenerationByPath, (ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path), (out, out_key_generation, path), hos::Version_3_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 610, Result, GetRightsIdAndKeyGenerationByPathObsolete, (ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path), (out, out_key_generation, path), hos::Version_3_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 610, Result, GetRightsIdAndKeyGenerationByPath, (ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr), (out, out_key_generation, path, attr), hos::Version_16_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 611, Result, SetCurrentPosixTimeWithTimeDifference, (s64 posix_time, s32 time_difference), (posix_time, time_difference), hos::Version_4_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 611, Result, SetCurrentPosixTimeWithTimeDifference, (s64 posix_time, s32 time_difference), (posix_time, time_difference), hos::Version_4_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 612, Result, GetFreeSpaceSizeForSaveData, (ams::sf::Out<s64> out, u8 space_id), (out, space_id), hos::Version_4_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 612, Result, GetFreeSpaceSizeForSaveData, (ams::sf::Out<s64> out, u8 space_id), (out, space_id), hos::Version_4_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 613, Result, VerifySaveDataFileSystemBySaveDataSpaceId, (), (), hos::Version_4_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 613, Result, VerifySaveDataFileSystemBySaveDataSpaceId, (), (), hos::Version_4_0_0) \
|
||||||
|
|||||||
@@ -18,12 +18,14 @@
|
|||||||
#include <stratosphere/sf.hpp>
|
#include <stratosphere/sf.hpp>
|
||||||
#include <stratosphere/fssrv/sf/fssrv_sf_ifilesystem.hpp>
|
#include <stratosphere/fssrv/sf/fssrv_sf_ifilesystem.hpp>
|
||||||
#include <stratosphere/fs/fs_code_verification_data.hpp>
|
#include <stratosphere/fs/fs_code_verification_data.hpp>
|
||||||
|
#include <stratosphere/fs/fs_content_attributes.hpp>
|
||||||
|
|
||||||
/* ACCURATE_TO_VERSION: 13.4.0.0 */
|
/* ACCURATE_TO_VERSION: 13.4.0.0 */
|
||||||
#define AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO(C, H) \
|
#define AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO(C, H) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, path, program_id), hos::Version_Min, hos::Version_9_2_0) \
|
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, path, program_id), hos::Version_Min, hos::Version_9_2_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, out_verif, path, program_id), hos::Version_10_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated2, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, out_verif, path, program_id), hos::Version_10_0_0, hos::Version_15_0_1) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 1, Result, IsArchivedProgram, (ams::sf::Out<bool> out, u64 process_id), (out, process_id)) \
|
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id), (out_fs, out_verif, path, attr, program_id), hos::Version_16_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 2, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid), hos::Version_4_0_0)
|
AMS_SF_METHOD_INFO(C, H, 1, Result, IsArchivedProgram, (ams::sf::Out<bool> out, u64 process_id), (out, process_id)) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 2, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid), hos::Version_4_0_0)
|
||||||
|
|
||||||
AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IFileSystemProxyForLoader, AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO, 0xDC92EE15)
|
AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IFileSystemProxyForLoader, AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO, 0xDC92EE15)
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ namespace ams::hos {
|
|||||||
Version_14_1_1 = ::ams::TargetFirmware_14_1_1,
|
Version_14_1_1 = ::ams::TargetFirmware_14_1_1,
|
||||||
Version_14_1_2 = ::ams::TargetFirmware_14_1_2,
|
Version_14_1_2 = ::ams::TargetFirmware_14_1_2,
|
||||||
Version_15_0_0 = ::ams::TargetFirmware_15_0_0,
|
Version_15_0_0 = ::ams::TargetFirmware_15_0_0,
|
||||||
|
Version_15_0_1 = ::ams::TargetFirmware_15_0_1,
|
||||||
|
Version_16_0_0 = ::ams::TargetFirmware_16_0_0,
|
||||||
|
Version_16_0_1 = ::ams::TargetFirmware_16_0_1,
|
||||||
|
Version_16_0_2 = ::ams::TargetFirmware_16_0_2,
|
||||||
|
Version_16_0_3 = ::ams::TargetFirmware_16_0_3,
|
||||||
|
|
||||||
Version_Current = ::ams::TargetFirmware_Current,
|
Version_Current = ::ams::TargetFirmware_Current,
|
||||||
|
|
||||||
|
|||||||
@@ -279,6 +279,23 @@ namespace ams::kvdb {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result InitializeForReadOnlyArchiveFile(const char *path, size_t capacity, MemoryResource *mr) {
|
||||||
|
/* Ensure that the passed path is a directory. */
|
||||||
|
fs::DirectoryEntryType entry_type;
|
||||||
|
R_TRY(fs::GetEntryType(std::addressof(entry_type), path));
|
||||||
|
R_UNLESS(entry_type == fs::DirectoryEntryType_File, fs::ResultPathNotFound());
|
||||||
|
|
||||||
|
/* Set paths. */
|
||||||
|
m_path.Assign(path);
|
||||||
|
m_temp_path.Assign("");
|
||||||
|
|
||||||
|
/* Initialize our index. */
|
||||||
|
R_TRY(m_index.Initialize(capacity, mr));
|
||||||
|
m_memory_resource = mr;
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result Initialize(size_t capacity, MemoryResource *mr) {
|
Result Initialize(size_t capacity, MemoryResource *mr) {
|
||||||
/* This initializes without an archive file. */
|
/* This initializes without an archive file. */
|
||||||
/* A store initialized this way cannot have its contents loaded from or flushed to disk. */
|
/* A store initialized this way cannot have its contents loaded from or flushed to disk. */
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <stratosphere/ncm/ncm_content_meta_database.hpp>
|
#include <stratosphere/ncm/ncm_content_meta_database.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_storage.hpp>
|
#include <stratosphere/ncm/ncm_content_storage.hpp>
|
||||||
#include <stratosphere/ncm/ncm_i_content_manager.hpp>
|
#include <stratosphere/ncm/ncm_i_content_manager.hpp>
|
||||||
|
#include <stratosphere/fs/fs_content_storage_id.hpp>
|
||||||
|
|
||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
|
|
||||||
@@ -46,6 +47,8 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
Result InvalidateRightsIdCache();
|
Result InvalidateRightsIdCache();
|
||||||
|
|
||||||
|
Result ActivateFsContentStorage(fs::ContentStorageId fs_content_storage_id);
|
||||||
|
|
||||||
/* Deprecated API. */
|
/* Deprecated API. */
|
||||||
Result CloseContentStorageForcibly(StorageId storage_id);
|
Result CloseContentStorageForcibly(StorageId storage_id);
|
||||||
Result CloseContentMetaDatabaseForcibly(StorageId storage_id);
|
Result CloseContentMetaDatabaseForcibly(StorageId storage_id);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
|
|
||||||
struct alignas(4) ContentId {
|
struct ContentId {
|
||||||
util::Uuid uuid;
|
util::Uuid uuid;
|
||||||
|
|
||||||
bool operator==(const ContentId &other) const {
|
bool operator==(const ContentId &other) const {
|
||||||
@@ -38,7 +38,7 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(alignof(ContentId) == 4);
|
static_assert(alignof(ContentId) == 1);
|
||||||
|
|
||||||
constexpr inline ContentId InvalidContentId = { util::InvalidUuid };
|
constexpr inline ContentId InvalidContentId = { util::InvalidUuid };
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ namespace ams::ncm {
|
|||||||
struct ContentManagerConfig {
|
struct ContentManagerConfig {
|
||||||
bool build_system_database;
|
bool build_system_database;
|
||||||
bool import_database_from_system_on_sd;
|
bool import_database_from_system_on_sd;
|
||||||
|
bool enable_integrated_system_content;
|
||||||
|
|
||||||
bool HasAnyConfig() const {
|
bool HasAnyConfig() const {
|
||||||
return this->ShouldBuildDatabase() || this->import_database_from_system_on_sd;
|
return this->ShouldBuildDatabase() || this->import_database_from_system_on_sd || this->enable_integrated_system_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldBuildDatabase() const {
|
bool ShouldBuildDatabase() const {
|
||||||
@@ -33,6 +34,10 @@ namespace ams::ncm {
|
|||||||
bool ShouldImportDatabaseFromSignedSystemPartitionOnSd() const {
|
bool ShouldImportDatabaseFromSignedSystemPartitionOnSd() const {
|
||||||
return this->import_database_from_system_on_sd;
|
return this->import_database_from_system_on_sd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsIntegratedSystemContentEnabled() const {
|
||||||
|
return this->enable_integrated_system_content;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include <stratosphere/ncm/ncm_content_management_utils.hpp>
|
#include <stratosphere/ncm/ncm_content_management_utils.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_meta_utils.hpp>
|
#include <stratosphere/ncm/ncm_content_meta_utils.hpp>
|
||||||
#include <stratosphere/ncm/ncm_registered_host_content.hpp>
|
#include <stratosphere/ncm/ncm_registered_host_content.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_integrated_content_meta_database_impl.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_integrated_content_storage_impl.hpp>
|
||||||
#include <stratosphere/kvdb/kvdb_memory_key_value_store.hpp>
|
#include <stratosphere/kvdb/kvdb_memory_key_value_store.hpp>
|
||||||
|
|
||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
@@ -69,10 +71,29 @@ namespace ams::ncm {
|
|||||||
};
|
};
|
||||||
static_assert(util::is_pod<SystemSaveDataInfo>::value);
|
static_assert(util::is_pod<SystemSaveDataInfo>::value);
|
||||||
|
|
||||||
|
struct IntegratedContentStorageImpl;
|
||||||
|
|
||||||
class ContentManagerImpl {
|
class ContentManagerImpl {
|
||||||
private:
|
private:
|
||||||
constexpr static size_t MaxContentStorageRoots = 8;
|
constexpr static size_t MaxContentStorageRoots = 8;
|
||||||
constexpr static size_t MaxContentMetaDatabaseRoots = 8;
|
constexpr static size_t MaxIntegratedContentStorageRoots = 8;
|
||||||
|
constexpr static size_t MaxContentMetaDatabaseRoots = 8;
|
||||||
|
constexpr static size_t MaxIntegratedContentMetaDatabaseRoots = 8;
|
||||||
|
constexpr static size_t MaxConfigs = 8;
|
||||||
|
constexpr static size_t MaxIntegratedConfigs = 8;
|
||||||
|
private:
|
||||||
|
struct ContentStorageConfig {
|
||||||
|
fs::ContentStorageId content_storage_id;
|
||||||
|
bool skip_verify_and_create;
|
||||||
|
bool skip_activate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IntegratedContentStorageConfig {
|
||||||
|
ncm::StorageId storage_id;
|
||||||
|
fs::ContentStorageId content_storage_ids[MaxContentStorageRoots];
|
||||||
|
int num_content_storage_ids;
|
||||||
|
bool is_integrated;
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
struct ContentStorageRoot {
|
struct ContentStorageRoot {
|
||||||
NON_COPYABLE(ContentStorageRoot);
|
NON_COPYABLE(ContentStorageRoot);
|
||||||
@@ -81,10 +102,42 @@ namespace ams::ncm {
|
|||||||
char mount_name[fs::MountNameLengthMax + 1];
|
char mount_name[fs::MountNameLengthMax + 1];
|
||||||
char path[128];
|
char path[128];
|
||||||
StorageId storage_id;
|
StorageId storage_id;
|
||||||
fs::ContentStorageId content_storage_id;
|
util::optional<ContentStorageConfig> config;
|
||||||
sf::SharedPointer<IContentStorage> content_storage;
|
sf::SharedPointer<IContentStorage> content_storage;
|
||||||
|
|
||||||
ContentStorageRoot() : mount_name(), path(), storage_id(), content_storage_id(), content_storage() { /* ... */ }
|
ContentStorageRoot() : mount_name(), path(), storage_id(), config(util::nullopt), content_storage() { /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IntegratedContentStorageRoot {
|
||||||
|
NON_COPYABLE(IntegratedContentStorageRoot);
|
||||||
|
NON_MOVEABLE(IntegratedContentStorageRoot);
|
||||||
|
|
||||||
|
const IntegratedContentStorageConfig *m_config;
|
||||||
|
ContentStorageRoot *m_roots;
|
||||||
|
int m_num_roots;
|
||||||
|
sf::EmplacedRef<IContentStorage, IntegratedContentStorageImpl> m_integrated_content_storage;
|
||||||
|
|
||||||
|
IntegratedContentStorageRoot() : m_config(), m_roots(), m_num_roots(), m_integrated_content_storage() { /* ... */ }
|
||||||
|
|
||||||
|
Result Create();
|
||||||
|
Result Verify();
|
||||||
|
Result Open(sf::Out<sf::SharedPointer<IContentStorage>> out, RightsIdCache &rights_id_cache, RegisteredHostContent ®istered_host_content);
|
||||||
|
Result Activate(RightsIdCache &rights_id_cache, RegisteredHostContent ®istered_host_content);
|
||||||
|
Result Inactivate(RegisteredHostContent ®istered_host_content);
|
||||||
|
|
||||||
|
Result Activate(ContentStorageRoot &root, RightsIdCache &rights_id_cache, RegisteredHostContent ®istered_host_content);
|
||||||
|
|
||||||
|
Result Activate(RightsIdCache &rights_id_cache, RegisteredHostContent ®istered_host_content, fs::ContentStorageId content_storage_id);
|
||||||
|
|
||||||
|
ContentStorageRoot *GetRoot(fs::ContentStorageId storage_id) {
|
||||||
|
for (auto i = 0; i < m_num_roots; ++i) {
|
||||||
|
if (auto &root = m_roots[i]; root.config.has_value() && root.config->content_storage_id == storage_id) {
|
||||||
|
return std::addressof(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ContentMetaDatabaseRoot {
|
struct ContentMetaDatabaseRoot {
|
||||||
@@ -94,46 +147,100 @@ namespace ams::ncm {
|
|||||||
char mount_name[fs::MountNameLengthMax + 1];
|
char mount_name[fs::MountNameLengthMax + 1];
|
||||||
char path[128];
|
char path[128];
|
||||||
StorageId storage_id;
|
StorageId storage_id;
|
||||||
SystemSaveDataInfo info;
|
util::optional<ContentStorageConfig> storage_config;
|
||||||
sf::SharedPointer<IContentMetaDatabase> content_meta_database;
|
util::optional<SystemSaveDataInfo> save_data_info;
|
||||||
util::optional<kvdb::MemoryKeyValueStore<ContentMetaKey>> kvs;
|
util::optional<kvdb::MemoryKeyValueStore<ContentMetaKey>> kvs;
|
||||||
|
sf::SharedPointer<IContentMetaDatabase> content_meta_database;
|
||||||
ContentMetaMemoryResource *memory_resource;
|
ContentMetaMemoryResource *memory_resource;
|
||||||
u32 max_content_metas;
|
u32 max_content_metas;
|
||||||
|
|
||||||
ContentMetaDatabaseRoot() : mount_name(), path(), storage_id(), info(), content_meta_database(), kvs(util::nullopt), memory_resource(), max_content_metas() { /* ... */ }
|
ContentMetaDatabaseRoot() : mount_name(), path(), storage_id(), storage_config(util::nullopt), save_data_info(util::nullopt), kvs(util::nullopt), content_meta_database(), memory_resource(), max_content_metas() { /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IntegratedContentMetaDatabaseRoot {
|
||||||
|
NON_COPYABLE(IntegratedContentMetaDatabaseRoot);
|
||||||
|
NON_MOVEABLE(IntegratedContentMetaDatabaseRoot);
|
||||||
|
|
||||||
|
const IntegratedContentStorageConfig *m_config;
|
||||||
|
ContentMetaDatabaseRoot *m_roots;
|
||||||
|
int m_num_roots;
|
||||||
|
sf::EmplacedRef<IContentMetaDatabase, IntegratedContentMetaDatabaseImpl> m_integrated_content_meta_database;
|
||||||
|
|
||||||
|
IntegratedContentMetaDatabaseRoot() : m_config(), m_roots(), m_num_roots(), m_integrated_content_meta_database() { /* ... */ }
|
||||||
|
|
||||||
|
Result Create();
|
||||||
|
Result Verify();
|
||||||
|
Result Open(sf::Out<sf::SharedPointer<IContentMetaDatabase>> out);
|
||||||
|
Result Cleanup();
|
||||||
|
Result Activate();
|
||||||
|
Result Inactivate();
|
||||||
|
|
||||||
|
Result Activate(ContentMetaDatabaseRoot &root);
|
||||||
|
|
||||||
|
Result Activate(fs::ContentStorageId content_storage_id);
|
||||||
|
|
||||||
|
ContentMetaDatabaseRoot *GetRoot(fs::ContentStorageId storage_id) {
|
||||||
|
for (auto i = 0; i < m_num_roots; ++i) {
|
||||||
|
if (auto &root = m_roots[i]; root.storage_config.has_value() && root.storage_config->content_storage_id == storage_id) {
|
||||||
|
return std::addressof(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
os::SdkRecursiveMutex m_mutex;
|
os::SdkRecursiveMutex m_mutex{};
|
||||||
bool m_initialized;
|
bool m_initialized{false};
|
||||||
ContentStorageRoot m_content_storage_roots[MaxContentStorageRoots];
|
IntegratedContentStorageRoot m_integrated_content_storage_roots[MaxIntegratedContentStorageRoots]{};
|
||||||
ContentMetaDatabaseRoot m_content_meta_database_roots[MaxContentMetaDatabaseRoots];
|
ContentStorageRoot m_content_storage_roots[MaxContentStorageRoots]{};
|
||||||
u32 m_num_content_storage_entries;
|
IntegratedContentMetaDatabaseRoot m_integrated_content_meta_database_roots[MaxIntegratedContentMetaDatabaseRoots]{};
|
||||||
u32 m_num_content_meta_entries;
|
ContentMetaDatabaseRoot m_content_meta_database_roots[MaxContentMetaDatabaseRoots]{};
|
||||||
RightsIdCache m_rights_id_cache;
|
IntegratedContentStorageConfig m_integrated_configs[MaxIntegratedConfigs]{};
|
||||||
RegisteredHostContent m_registered_host_content;
|
ContentStorageConfig m_configs[MaxConfigs]{};
|
||||||
|
u32 m_num_integrated_content_storage_entries{0};
|
||||||
|
u32 m_num_content_storage_entries{0};
|
||||||
|
u32 m_num_integrated_content_meta_entries{0};
|
||||||
|
u32 m_num_content_meta_entries{0};
|
||||||
|
u32 m_num_integrated_configs{0};
|
||||||
|
u32 m_num_configs{0};
|
||||||
|
RightsIdCache m_rights_id_cache{};
|
||||||
|
RegisteredHostContent m_registered_host_content{};
|
||||||
public:
|
public:
|
||||||
ContentManagerImpl() : m_mutex(), m_initialized(false), m_content_storage_roots(), m_content_meta_database_roots(), m_num_content_storage_entries(0), m_num_content_meta_entries(0), m_rights_id_cache(), m_registered_host_content() {
|
ContentManagerImpl() = default;
|
||||||
/* ... */
|
|
||||||
};
|
|
||||||
~ContentManagerImpl();
|
~ContentManagerImpl();
|
||||||
public:
|
public:
|
||||||
Result Initialize(const ContentManagerConfig &config);
|
Result Initialize(const ContentManagerConfig &config);
|
||||||
|
private:
|
||||||
|
Result Initialize(const ContentManagerConfig &manager_config, const IntegratedContentStorageConfig *integrated_configs, size_t num_integrated_configs, const ContentStorageConfig *configs, size_t num_configs, const ncm::StorageId *activated_storages, size_t num_activated_storages);
|
||||||
|
Result InitializeStorageBuiltInSystem(const ContentManagerConfig &manager_config);
|
||||||
|
Result InitializeStorage(ncm::StorageId storage_id);
|
||||||
|
|
||||||
|
const ContentStorageConfig &GetContentStorageConfig(fs::ContentStorageId content_storage_id) {
|
||||||
|
for (size_t i = 0; i < m_num_configs; ++i) {
|
||||||
|
if (m_configs[i].content_storage_id == content_storage_id) {
|
||||||
|
return m_configs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: Nintendo accesses out of bounds memory here. Should we explicitly abort? This is guaranteed by data to never happen. */
|
||||||
|
AMS_ASSUME(false);
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
/* Helpers. */
|
/* Helpers. */
|
||||||
Result GetContentStorageRoot(ContentStorageRoot **out, StorageId id);
|
Result GetIntegratedContentStorageConfig(IntegratedContentStorageConfig **out, fs::ContentStorageId content_storage_id);
|
||||||
Result GetContentMetaDatabaseRoot(ContentMetaDatabaseRoot **out, StorageId id);
|
Result GetIntegratedContentStorageRoot(IntegratedContentStorageRoot **out, StorageId id);
|
||||||
|
Result GetIntegratedContentMetaDatabaseRoot(IntegratedContentMetaDatabaseRoot **out, StorageId id);
|
||||||
|
|
||||||
Result InitializeContentStorageRoot(ContentStorageRoot *out, StorageId storage_id, fs::ContentStorageId content_storage_id);
|
Result InitializeContentStorageRoot(ContentStorageRoot *out, StorageId storage_id, util::optional<ContentStorageConfig> config);
|
||||||
Result InitializeGameCardContentStorageRoot(ContentStorageRoot *out);
|
Result InitializeContentMetaDatabaseRoot(ContentMetaDatabaseRoot *out, StorageId storage_id, util::optional<ContentStorageConfig> storage_config);
|
||||||
|
|
||||||
Result InitializeContentMetaDatabaseRoot(ContentMetaDatabaseRoot *out, StorageId storage_id, const SystemSaveDataInfo &info, size_t max_content_metas, ContentMetaMemoryResource *mr);
|
Result InitializeIntegratedContentStorageRoot(IntegratedContentStorageRoot *out, const IntegratedContentStorageConfig *config, size_t root_idx, size_t root_count);
|
||||||
Result InitializeGameCardContentMetaDatabaseRoot(ContentMetaDatabaseRoot *out, size_t max_content_metas, ContentMetaMemoryResource *mr);
|
Result InitializeIntegratedContentMetaDatabaseRoot(IntegratedContentMetaDatabaseRoot *out, const IntegratedContentStorageConfig *config, size_t root_idx, size_t root_count);
|
||||||
|
|
||||||
Result BuildContentMetaDatabase(StorageId storage_id);
|
Result BuildContentMetaDatabase(StorageId storage_id);
|
||||||
Result ImportContentMetaDatabase(StorageId storage_id, bool from_signed_partition);
|
Result ImportContentMetaDatabase(StorageId storage_id, bool from_signed_partition);
|
||||||
Result ImportContentMetaDatabaseImpl(StorageId storage_id, const char *import_mount_name, const char *path);
|
Result ImportContentMetaDatabaseImpl(ContentMetaDatabaseRoot *root, const char *import_mount_name);
|
||||||
|
|
||||||
Result EnsureAndMountSystemSaveData(const char *mount, const SystemSaveDataInfo &info) const;
|
|
||||||
public:
|
public:
|
||||||
/* Actual commands. */
|
/* Actual commands. */
|
||||||
Result CreateContentStorage(StorageId storage_id);
|
Result CreateContentStorage(StorageId storage_id);
|
||||||
@@ -151,6 +258,7 @@ namespace ams::ncm {
|
|||||||
Result InactivateContentMetaDatabase(StorageId storage_id);
|
Result InactivateContentMetaDatabase(StorageId storage_id);
|
||||||
Result InvalidateRightsIdCache();
|
Result InvalidateRightsIdCache();
|
||||||
Result GetMemoryReport(sf::Out<MemoryReport> out);
|
Result GetMemoryReport(sf::Out<MemoryReport> out);
|
||||||
|
Result ActivateFsContentStorage(fs::ContentStorageId fs_content_storage_id);
|
||||||
};
|
};
|
||||||
static_assert(IsIContentManager<ContentManagerImpl>);
|
static_assert(IsIContentManager<ContentManagerImpl>);
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user