Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80cae0cc2d | ||
|
|
e780171c78 | ||
|
|
0cbf726479 | ||
|
|
a192ca5172 | ||
|
|
cbebfcb9e2 | ||
|
|
ec950d8320 | ||
|
|
d562bb841d | ||
|
|
ff1760fac1 | ||
|
|
7ea4737abb | ||
|
|
0a1ce6f079 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -91,11 +91,7 @@ dkms.conf
|
||||
**/out
|
||||
**/build
|
||||
**/build_nintendo_nx_arm64
|
||||
**/build_nintendo_nx_arm64_armv8a
|
||||
**/build_nintendo_nx_arm
|
||||
**/build_nintendo_nx_arm_armv8a
|
||||
**/build_nintendo_nx_arm_armv7a
|
||||
**/build_nintendo_nx_arm_armv4t
|
||||
**/build_nintendo_nx_x64
|
||||
**/build_nintendo_nx_x86
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@@ -112,7 +112,6 @@ dist-no-debug: all
|
||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042
|
||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420
|
||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240
|
||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D609
|
||||
mkdir -p atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623
|
||||
cp stratosphere/boot2/boot2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000008/exefs.nsp
|
||||
cp stratosphere/dmnt/dmnt.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000000D/exefs.nsp
|
||||
@@ -126,7 +125,6 @@ dist-no-debug: all
|
||||
cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
|
||||
cp stratosphere/LogManager/LogManager.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp
|
||||
cp stratosphere/htc/htc.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000B240/exefs.nsp
|
||||
cp stratosphere/dmnt.gen2/dmnt.gen2.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D609/exefs.nsp
|
||||
cp stratosphere/TioServer/TioServer.nsp atmosphere-$(AMSVER)/stratosphere_romfs/atmosphere/contents/010000000000D623/exefs.nsp
|
||||
@build_romfs atmosphere-$(AMSVER)/stratosphere_romfs atmosphere-$(AMSVER)/atmosphere/stratosphere.romfs
|
||||
rm -r atmosphere-$(AMSVER)/stratosphere_romfs
|
||||
|
||||
@@ -1,112 +1,4 @@
|
||||
# Changelog
|
||||
## 1.2.6
|
||||
+ Support was added for 13.2.1.
|
||||
+ A number of minor issues were fixed and improvements were made, including:
|
||||
+ A minor performance improvement was implemented in service table dispatch by sorting and binary-searching the service command table instead of using linear search.
|
||||
+ Static initialization logic in Atmosphere was made much more regular.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 1.2.5
|
||||
+ Support was added for 13.2.0.
|
||||
+ A number of minor issues were fixed and improvements were made, including:
|
||||
+ A bug was fixed that caused `mesosphère` to underreport the total memory size by 8MB for certain games which use newer system-resource-size memory management.
|
||||
+ This caused FIFA 19 to crash, and possibly other issues.
|
||||
+ Memory management changes were made to `sm` that save 0x5000 of memory.
|
||||
+ A microoptimization was made to the way `mesosphère` manages updating the debug register for hardware single-step support.
|
||||
+ Support was fixed for enabling `usb!usb30_force_enabled` on 13.0.0+.
|
||||
+ The work-in-progress unit testing framework was updated to use doctest instead of catch2.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 1.2.4
|
||||
+ Changes were made to the way fs.mitm builds images when providing a layeredfs romfs.
|
||||
+ Cache management (to avoid unnecessary rebuild) was revised, to add a grace period of ~500ms-1s between process closing romfs image and ams.mitm needing to rebuild if romfs is re-opened.
|
||||
+ This makes our cache much more effective, previously we were re-building romfs several times.
|
||||
+ RomFS image ownership was overhauled, with a new reference-counting implementation added (used to implement the above grace period).
|
||||
+ Certain games (e.g. Puyo Puyo Tetris 2, probably others) were sensitive to this timing, and could use access patterns which would trigger creation of romfs image while previous romfs image was in the middle of destructor.
|
||||
+ This could cause a fatal error, because the destructor for the old image could run simultaneously with building the new image.
|
||||
+ This also provides a speedup versus the 1.2.3 code, with Animal Crossing now taking ~8 fewer seconds to get past the Nintendo Switch logo.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 1.2.3
|
||||
+ Because ams.TMA is taking longer to develop than expected, experimental support for Atmosphère's gdbstub as a standalone is now available.
|
||||
+ To enable it, set `atmosphere!enable_standalone_gdbstub` = u8!0x1 in system_settings.ini.
|
||||
+ The standalone also requires `atmosphere!enable_htc` = u8!0x0, but this should be the case for everyone since ams.TMA isn't actually usable yet.
|
||||
+ Once enabled, open the devkitPro provided-gdb (`aarch64-none-elf-gdb` for 64-bit or `arm-none-eabi-gdb` for 32-bit).
|
||||
+ The standalone stub exposes itself on port 22225 -- so the command to connect is `target extended-remote <ip address>:22225`.
|
||||
+ Type `info os processes` to get a list of process IDs that can be attached to.
|
||||
+ The stub should work on both system programs, games, and homebrew -- but please note that debugging certain processes (like sockets) can cause hang due to the stub using them itself.
|
||||
+ Software break-points, hardware break-points, hardware watch-points, and hardware single-step are all supported/implemented.
|
||||
+ The following monitor commands are currently supported:
|
||||
+ `monitor get info`: Get process info, address space layout, and information on modules.
|
||||
+ `monitor get mappings`: Get all memory mappings.
|
||||
+ `monitor get mapping <addr>`: Get the memory mapping for a specific address.
|
||||
+ `monitor wait application`: Causes the stub to wait for an application to be launched. The next application will be started suspended.
|
||||
+ User is expected to send `attach <pid>` after launching, which will cause attach-on-first-instruction. Failure to attach may cause system instability, this probably needs work.
|
||||
+ **Please Note**: The GDBstub is new and may have bugs/need work. If you find issues, please report them to SciresM#0524 -- all help finding/fixing bugs is appreciated, here.
|
||||
+ Generally speaking, if you would like to report information about fixes needed/discuss development of the gdbstub, join ReSwitched's #dev-support channel.
|
||||
+ Changes were made to the way fs.mitm builds images when providing a layeredfs romfs.
|
||||
+ Animal Crossing's 2.0.0 update contains >99000 files, and has tables so big that we ran out of memory even after the optimizations made in 0.10.5.
|
||||
+ Previously, we used fixed-sized 0x40000 work buffers for file/directory tables and simultaneously built hash/content tables in one loop over files/directories.
|
||||
+ We now iterate over the file/directory tables multiple times, first once to determine the hash table indices, then repeatedly to build hash tables, then once to build content tables.
|
||||
+ We also now allow smaller-than-0x40000 work buffers, trying half-as-big buffers until allocation succeeds (or work buffer would be <0x4000, which is a safeguard against truly horrible performance).
|
||||
+ There is a slight speed penalty to these changes, but it's on the order of seconds for the worst case (Animal Crossing) and trivial for most games with reasonable tables.
|
||||
+ If you encounter a game that exhausts ams.mitm's memory (crashing it) when loading layeredfs mods, please contact `SciresM#0524`.
|
||||
+ It's really hard to imagine any game being worse than Animal Crossing, but if it happens again I will drop everything to fix it as usual.
|
||||
+ `creport` now attempts to parse symbol tables if present.
|
||||
+ If a game executable has a symbol for a given address, the function-relative-offset will now be printed after the module-relative-offset.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 1.2.2
|
||||
+ A number of fixes were made to Atmosphère's implementation of the new "sprofile" service added in 13.0.0.
|
||||
+ Nintendo is finally transmitting data over the internet to certain consoles, which has allowed for validating our service implementation.
|
||||
+ Unfortunately, there were several problems, and if your console began trying to use the new services atmosphere would show a fatal error with code 0xCAF6 (sprofile::ResultInvalidState()).
|
||||
+ With actual test data in hand, a test program was written and it was verified that our implementation can successfully import/access profile data now.
|
||||
+ Hopefully there are no more issues, and I sincerely apologize for anyone who got an 0xCAF6 fatal due to this.
|
||||
+ A number of minor improvements were made to `mesosphère`, including:
|
||||
+ KThread::GetContextForSchedulerLoop was implemented in assembly (using static assertions to verify offset-of-context-in-struct is correct).
|
||||
+ This saves an unnecessary function call in the middle of the scheduler hot loop, replacing it with an addition instruction, which should improve microperformance.
|
||||
+ Mesosphere's hardware maintenance instructions were audited via a script and now directly match Nintendo's kernels.
|
||||
+ Notably, this inserts a missing instruction synchronization barrier when validating that slab heaps may be constructed.
|
||||
+ This missing ISB could cause an abort on certain (see: particularly sensitive) hardware on boot if the relevant codepath was speculatively executed (it normally only executes on game launch...)
|
||||
+ The SVC handlers for performing light IPC (normally unused) from 32-bit process were fixed in Mesosphere.
|
||||
+ A bug was fixed that would cause the register x27 to be overwritten with the contents of x26 when returning from a user exception handler.
|
||||
+ A bug was fixed that would cause the kernel to use the userland stack pointer instead of the kernel stack pointer while generating an error report for a kernel abort.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 1.2.1
|
||||
+ Support was implemented for 13.1.0.
|
||||
+ `mesosphère` was updated to reflect the kernel behavioral changes made in 13.1.0.
|
||||
+ KScheduler now issues a data memory barrier when unlocking the scheduler lock and when early-returning due to top-thread-is-current during scheduling.
|
||||
+ `erpt` was updated to reflect the latest official behaviors.
|
||||
+ The new service added in 13.0.0 ("sprofile") was revised, and the data formats it expects was changed.
|
||||
+ This still appears to be (possibly(?)) untestable due to data not being transmitted yet, but I have greater confidence things will go smoothly than I did when 1.1.0 released.
|
||||
+ A number of improvements were made to `mesosphère`, including:
|
||||
+ A build target was created to build targeting the qemu `virt` board.
|
||||
+ This facilitates writing unit tests for the kernel (and other atmosphere components) and running them under PC.
|
||||
+ **Please Note**: Official system software will not work at all under this, and the Atmosphère project has zero interest in attempting to run official software of any kind. This is unit testing machinery, and explicitly not more than that.
|
||||
+ This should hopefully allow us to have greater confidence that all of atmosphere's components work the way they're theoretically supposed to in the future.
|
||||
+ **Please Note**: If you are a developer who is familiar with the Horizon operating system (or capable of becoming familiar), I would greatly appreciate help writing tests and improving the testing framework.
|
||||
+ Please contact `SciresM#0524` if you are capable and interested.
|
||||
+ Really, if you are actually a developer who would like to help me get this off the ground, I would deeply appreciate it.
|
||||
+ That said, if you are not a developer but want to be one, this probably isn't the best opportunity; I expect it to be highly technical.
|
||||
+ Consider the ReSwitched discord's #hack-n-all channel for your educational purposes.
|
||||
+ We are (at least for now) using [catch2](https://github.com/catchorg/Catch2) for unit tests.
|
||||
+ Almost all virtual calls in the kernel are now resolved statically.
|
||||
+ This eliminates substantial virtual call overhead, and should lead to improved kernel microperformance in pretty much every function.
|
||||
+ The remaining red black tree find operations which weren't using the optimized "find key" variant are now using the optimized version.
|
||||
+ Custom assembly was written to improve tick-to-timespan conversion.
|
||||
+ This works around gcc emitting suboptimal assembly at -Os (it emits good assembly at -O3, clang is fine at both -O3 and -Os).
|
||||
+ KThread and KSession structures were updated to optimize member layout, saving 0x10 bytes per KThread/KSession object.
|
||||
+ Rather than unnecessarily zero-ing all data in kernel objects only to overwrite members later, we now only initialize the members we need to in kernel object constructors.
|
||||
+ This is what Nintendo was doing already.
|
||||
+ A set of custom optimized atomic primitives were implemented and are used in place of std::atomic<>
|
||||
+ This works around a gcc bug which downgrades specified memory order to seq_cst, and introduces clrex in places where it is appropriate.
|
||||
+ This should strictly improve microperformance of many system calls.
|
||||
+ An compile-time toggleable extension was added to support 40-bit physical addresses in MapRange capabilities (using currently reserved bits).
|
||||
+ A number of minor bugs were fixed, including:
|
||||
+ Initial cache management now better reflects official behavior.
|
||||
+ This fixes an issue that caused certain hardware with cache sensitivity to produce cryptic kernel panics during boot.
|
||||
+ Incorrect logic when checking thread priority capabilities was fixed to reflect official behavior.
|
||||
+ The scheduler was updated to reflect latest official behavior, and a number of minor bugs involving clz/ctz were fixed.
|
||||
+ Accesses to the processes local region were fixed to properly use kernel linear region, not userland pointers.
|
||||
+ The cache SVCs exposed for 32-bit processes now better reflect official core mask request semantics.
|
||||
+ A bug was fixed that could cause a kernel panic if SvcArbitrateLock was called on a thread with exactly one reference in the middle of handling a user-mode exception.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 1.2.0
|
||||
+ `boot` was updated to reflect the latest official behavior for display/battery management.
|
||||
+ This should fix any issues that might result from running older releases on the OLED model, if you're somehow in a position to do so.
|
||||
|
||||
6
emummc/.gitrepo
vendored
6
emummc/.gitrepo
vendored
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/m4xw/emuMMC
|
||||
branch = develop
|
||||
commit = a9d56959460fc794ce2cb6405402c25a3e89c47f
|
||||
parent = ff719641396c635b735873fb2b020c910f768a04
|
||||
method = merge
|
||||
commit = f66087313546161a000ee196a788f0626caf80fa
|
||||
parent = 38f9a76ba028995ed3274da3a45b0254f09d1f59
|
||||
method = rebase
|
||||
cmdver = 0.4.1
|
||||
|
||||
16
emummc/README.md
vendored
16
emummc/README.md
vendored
@@ -1,21 +1,21 @@
|
||||
# emuMMC
|
||||
*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
|
||||
**1.0.0 - 13.1.0**
|
||||
**1.0.0 - 13.0.0**
|
||||
|
||||
## Features
|
||||
* Arbitrary SDMMC backend selection
|
||||
* Arbitrary SDMMC backend selection
|
||||
**This allows loading eMMC from SD or even SD from eMMC**
|
||||
* On the fly hooking / patching, fully self-infesting
|
||||
* On the fly hooking / patching, fully self-infesting
|
||||
**Only one payload required for all versions!**
|
||||
* File-based SDMMC backend support (from SD)
|
||||
* File-based SDMMC backend support (from SD)
|
||||
**This allows loading eMMC images from hekate-backups (split or not)**
|
||||
* SDMMC device based sector offset (*currently eMMC only*)
|
||||
* SDMMC device based sector offset (*currently eMMC only*)
|
||||
**Raw partition support for eMMC from SD with less performance overhead**
|
||||
* Full support for `/Nintendo` folder redirection to a arbitrary path
|
||||
* Full support for `/Nintendo` folder redirection to a arbitrary path
|
||||
**No 8 char length restriction!**
|
||||
* exosphere based context configuration
|
||||
* exosphere based context configuration
|
||||
**This includes full support for multiple emuMMC images**
|
||||
|
||||
## Compiling
|
||||
|
||||
8
emummc/source/FS/FS_offsets.c
vendored
8
emummc/source/FS/FS_offsets.c
vendored
@@ -57,8 +57,6 @@
|
||||
#include "offsets/1203_exfat.h"
|
||||
#include "offsets/1300.h"
|
||||
#include "offsets/1300_exfat.h"
|
||||
#include "offsets/1310.h"
|
||||
#include "offsets/1310_exfat.h"
|
||||
#include "../utils/fatal.h"
|
||||
|
||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
||||
@@ -127,8 +125,6 @@ DEFINE_OFFSET_STRUCT(_1203);
|
||||
DEFINE_OFFSET_STRUCT(_1203_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1300);
|
||||
DEFINE_OFFSET_STRUCT(_1300_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1310);
|
||||
DEFINE_OFFSET_STRUCT(_1310_EXFAT);
|
||||
|
||||
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
switch (version) {
|
||||
@@ -214,10 +210,6 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1300));
|
||||
case FS_VER_13_0_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1300_EXFAT));
|
||||
case FS_VER_13_1_0:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1310));
|
||||
case FS_VER_13_1_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1310_EXFAT));
|
||||
default:
|
||||
fatal_abort(Fatal_UnknownVersion);
|
||||
}
|
||||
|
||||
3
emummc/source/FS/FS_versions.h
vendored
3
emummc/source/FS/FS_versions.h
vendored
@@ -83,9 +83,6 @@ enum FS_VER
|
||||
FS_VER_13_0_0,
|
||||
FS_VER_13_0_0_EXFAT,
|
||||
|
||||
FS_VER_13_1_0,
|
||||
FS_VER_13_1_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
};
|
||||
|
||||
|
||||
59
emummc/source/FS/offsets/1310.h
vendored
59
emummc/source/FS/offsets/1310.h
vendored
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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_1310_H__
|
||||
#define __FS_1310_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1310_SDMMC_ACCESSOR_GC 0x158C20
|
||||
#define FS_OFFSET_1310_SDMMC_ACCESSOR_SD 0x15AA30
|
||||
#define FS_OFFSET_1310_SDMMC_ACCESSOR_NAND 0x159150
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1310_SDMMC_WRAPPER_READ 0x1545C0
|
||||
#define FS_OFFSET_1310_SDMMC_WRAPPER_WRITE 0x154680
|
||||
#define FS_OFFSET_1310_RTLD 0x688
|
||||
#define FS_OFFSET_1310_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||
|
||||
#define FS_OFFSET_1310_CLKRST_SET_MIN_V_CLK_RATE 0x1537C0
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1310_LOCK_MUTEX 0x29690
|
||||
#define FS_OFFSET_1310_UNLOCK_MUTEX 0x296E0
|
||||
|
||||
#define FS_OFFSET_1310_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1544A0
|
||||
#define FS_OFFSET_1310_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x154530
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1310_SD_MUTEX 0xE133E8
|
||||
#define FS_OFFSET_1310_NAND_MUTEX 0xE0E768
|
||||
#define FS_OFFSET_1310_ACTIVE_PARTITION 0xE0E7A8
|
||||
#define FS_OFFSET_1310_SDMMC_DAS_HANDLE 0xDF6E18
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1310_SD_DAS_INIT 0x27744
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1310_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006EBE0, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007BEEC, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00082294, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0009422C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1310_H__
|
||||
59
emummc/source/FS/offsets/1310_exfat.h
vendored
59
emummc/source/FS/offsets/1310_exfat.h
vendored
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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_1310_EXFAT_H__
|
||||
#define __FS_1310_EXFAT_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_ACCESSOR_GC 0x158C20
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_ACCESSOR_SD 0x15AA30
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_ACCESSOR_NAND 0x159150
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_READ 0x1545C0
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_WRITE 0x154680
|
||||
#define FS_OFFSET_1310_EXFAT_RTLD 0x688
|
||||
#define FS_OFFSET_1310_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||
|
||||
#define FS_OFFSET_1310_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1537C0
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1310_EXFAT_LOCK_MUTEX 0x29690
|
||||
#define FS_OFFSET_1310_EXFAT_UNLOCK_MUTEX 0x296E0
|
||||
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1544A0
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x154530
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1310_EXFAT_SD_MUTEX 0xE203E8
|
||||
#define FS_OFFSET_1310_EXFAT_NAND_MUTEX 0xE1B768
|
||||
#define FS_OFFSET_1310_EXFAT_ACTIVE_PARTITION 0xE1B7A8
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_DAS_HANDLE 0xE03E18
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1310_EXFAT_SD_DAS_INIT 0x27744
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1310_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006EBE0, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007BEEC, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00082294, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0009422C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1310_EXFAT_H__
|
||||
@@ -249,8 +249,6 @@ namespace ams::nxboot {
|
||||
return ams::TargetFirmware_12_1_0;
|
||||
} else if (std::memcmp(package1 + 0x10, "20210805", 8) == 0) {
|
||||
return ams::TargetFirmware_13_0_0;
|
||||
} else if (std::memcmp(package1 + 0x10, "20220105", 8) == 0) {
|
||||
return ams::TargetFirmware_13_2_1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -150,9 +150,6 @@ namespace ams::nxboot {
|
||||
FsVersion_13_0_0,
|
||||
FsVersion_13_0_0_Exfat,
|
||||
|
||||
FsVersion_13_1_0,
|
||||
FsVersion_13_1_0_Exfat,
|
||||
|
||||
FsVersion_Count,
|
||||
};
|
||||
|
||||
@@ -218,9 +215,6 @@ namespace ams::nxboot {
|
||||
|
||||
{ 0x7D, 0x20, 0x05, 0x47, 0x17, 0x8A, 0x83, 0x6A }, /* FsVersion_13_0_0 */
|
||||
{ 0x51, 0xEB, 0xFA, 0x9C, 0xCF, 0x66, 0xC0, 0x9E }, /* FsVersion_13_0_0_Exfat */
|
||||
|
||||
{ 0x91, 0xBA, 0x65, 0xA2, 0x1C, 0x1D, 0x50, 0xAE }, /* FsVersion_13_1_0 */
|
||||
{ 0x76, 0x38, 0x27, 0xEE, 0x9C, 0x20, 0x7E, 0x5B }, /* FsVersion_13_1_0_Exfat */
|
||||
};
|
||||
|
||||
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
|
||||
@@ -609,11 +603,6 @@ namespace ams::nxboot {
|
||||
AddPatch(fs_meta, 0x159119, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x1426D0, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
case FsVersion_13_1_0:
|
||||
case FsVersion_13_1_0_Exfat:
|
||||
AddPatch(fs_meta, 0x1590B9, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x142670, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||
branch = master
|
||||
commit = 0d161b8588aa6482b84f3c44dd001055b01a047f
|
||||
parent = 4efa5d7dd0bfbdf89a6261af0aef3878ca784b05
|
||||
commit = cf765c0946cc5c828364ae6bfccddc4041304f28
|
||||
parent = 8634ea0f7c4f0e68adf2dfaaddc6ae1e225c4fc2
|
||||
method = merge
|
||||
cmdver = 0.4.1
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
include $(DEVKITPRO)/devkitARM/base_rules
|
||||
|
||||
export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM_V4T
|
||||
export ATMOSPHERE_SETTINGS +=
|
||||
export ATMOSPHERE_CFLAGS +=
|
||||
export ATMOSPHERE_CXXFLAGS +=
|
||||
export ATMOSPHERE_ASFLAGS +=
|
||||
@@ -1,11 +0,0 @@
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
include $(DEVKITPRO)/devkitA64/base_rules
|
||||
|
||||
export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM_V8A
|
||||
export ATMOSPHERE_SETTINGS +=
|
||||
export ATMOSPHERE_CFLAGS +=
|
||||
export ATMOSPHERE_CXXFLAGS +=
|
||||
export ATMOSPHERE_ASFLAGS +=
|
||||
@@ -39,9 +39,6 @@ export ATMOSPHERE_ARCH_NAME := arm64
|
||||
export ATMOSPHERE_BOARD_NAME := nintendo_nx
|
||||
export ATMOSPHERE_OS_NAME := horizon
|
||||
|
||||
export ATMOSPHERE_SUB_ARCH_DIR = armv8a
|
||||
export ATMOSPHERE_SUB_ARCH_NAME = armv8a
|
||||
|
||||
export ATMOSPHERE_CPU_EXTENSIONS := arm_crypto_extension aarch64_crypto_extension
|
||||
else ifeq ($(ATMOSPHERE_CPU),arm7tdmi)
|
||||
export ATMOSPHERE_ARCH_DIR := arm
|
||||
@@ -52,9 +49,6 @@ export ATMOSPHERE_ARCH_NAME := arm
|
||||
export ATMOSPHERE_BOARD_NAME := nintendo_nx
|
||||
export ATMOSPHERE_OS_NAME := horizon
|
||||
|
||||
export ATMOSPHERE_SUB_ARCH_DIR = armv4t
|
||||
export ATMOSPHERE_SUB_ARCH_NAME = armv4t
|
||||
|
||||
export ATMOSPHERE_CPU_EXTENSIONS :=
|
||||
endif
|
||||
|
||||
@@ -70,9 +64,6 @@ export ATMOSPHERE_ARCH_NAME := arm64
|
||||
export ATMOSPHERE_BOARD_NAME := qemu_virt
|
||||
export ATMOSPHERE_OS_NAME := horizon
|
||||
|
||||
export ATMOSPHERE_SUB_ARCH_DIR = armv8a
|
||||
export ATMOSPHERE_SUB_ARCH_NAME = armv8a
|
||||
|
||||
export ATMOSPHERE_CPU_EXTENSIONS := arm_crypto_extension aarch64_crypto_extension
|
||||
endif
|
||||
|
||||
@@ -94,27 +85,14 @@ export ATMOSPHERE_BOARD_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/board/$(ATMOSP
|
||||
export ATMOSPHERE_OS_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/os/$(ATMOSPHERE_OS_DIR)
|
||||
export ATMOSPHERE_CPU_MAKE_DIR := $(ATMOSPHERE_ARCH_MAKE_DIR)/cpu/$(ATMOSPHERE_CPU_DIR)
|
||||
|
||||
ifneq ($(strip $(ATMOSPHERE_SUB_ARCH_NAME)),)
|
||||
export ATMOSPHERE_LIBRARY_DIR := lib_$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)_$(ATMOSPHERE_SUB_ARCH_NAME)
|
||||
export ATMOSPHERE_BUILD_DIR := build_$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)_$(ATMOSPHERE_SUB_ARCH_NAME)
|
||||
else
|
||||
export ATMOSPHERE_LIBRARY_DIR := lib_$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)
|
||||
export ATMOSPHERE_BUILD_DIR := build_$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)
|
||||
endif
|
||||
|
||||
include $(ATMOSPHERE_ARCH_MAKE_DIR)/arch.mk
|
||||
include $(ATMOSPHERE_BOARD_MAKE_DIR)/board.mk
|
||||
include $(ATMOSPHERE_OS_MAKE_DIR)/os.mk
|
||||
include $(ATMOSPHERE_CPU_MAKE_DIR)/cpu.mk
|
||||
|
||||
|
||||
ifneq ($(strip $(ATMOSPHERE_SUB_ARCH_NAME)),)
|
||||
export ATMOSPHERE_SUB_ARCH_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/arch/$(ATMOSPHERE_SUB_ARCH_DIR)
|
||||
|
||||
include $(ATMOSPHERE_SUB_ARCH_MAKE_DIR)/arch.mk
|
||||
endif
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# get atmosphere git revision information
|
||||
#---------------------------------------------------------------------------------
|
||||
@@ -147,20 +125,12 @@ DATA := data
|
||||
INCLUDES := include
|
||||
|
||||
GENERAL_SOURCE_DIRS=$1 $(foreach d,$(filter-out $1/arch $1/board $1/os $1/cpu $1,$(wildcard $1/*)),$(if $(wildcard $d/.),$(filter-out $d,$(call GENERAL_SOURCE_DIRS,$d)) $d,))
|
||||
|
||||
SPECIFIC_SOURCE_DIRS=$(if $(wildcard $1/$2/$3/.*),$1/$2/$3 $(call DIR_WILDCARD,$1/$2/$3),$(if $(wildcard $1/$2/generic/.*), $1/$2/generic $(call DIR_WILDCARD,$1/$2/generic),))
|
||||
|
||||
ifneq ($(strip $(ATMOSPHERE_SUB_ARCH_NAME)),)
|
||||
SPECIFIC_SOURCE_DIRS_ARCH=$(if $(wildcard $1/$2/$3/.*),$1/$2/$3 $(call DIR_WILDCARD,$1/$2/$3),$(if $(wildcard $1/$2/$4/.*),$1/$2/$4 $(call DIR_WILDCARD,$1/$2/$4),$(if $(wildcard $1/$2/generic/.*), $1/$2/generic $(call DIR_WILDCARD,$1/$2/generic),)))
|
||||
else
|
||||
SPECIFIC_SOURCE_DIRS_ARCH=$(if $(wildcard $1/$2/$3/.*),$1/$2/$3 $(call DIR_WILDCARD,$1/$2/$3),$(if $(wildcard $1/$2/generic/.*), $1/$2/generic $(call DIR_WILDCARD,$1/$2/generic),))
|
||||
endif
|
||||
|
||||
UNFILTERED_SOURCE_DIRS=$1 $(foreach d,$(wildcard $1/*),$(if $(wildcard $d/.),$(call DIR_WILDCARD,$d) $d,))
|
||||
|
||||
ALL_SOURCE_DIRS=$(foreach d,$(call GENERAL_SOURCE_DIRS,$1), \
|
||||
$d \
|
||||
$(call SPECIFIC_SOURCE_DIRS_ARCH,$d,arch,$(ATMOSPHERE_ARCH_DIR),$(ATMOSPHERE_SUB_ARCH_DIR)) \
|
||||
$(call SPECIFIC_SOURCE_DIRS,$d,arch,$(ATMOSPHERE_ARCH_DIR)) \
|
||||
$(call SPECIFIC_SOURCE_DIRS,$d,board,$(ATMOSPHERE_BOARD_DIR)) \
|
||||
$(call SPECIFIC_SOURCE_DIRS,$d,os,$(ATMOSPHERE_OS_DIR)) \
|
||||
$(call SPECIFIC_SOURCE_DIRS,$d,cpu,$(ATMOSPHERE_ARCH_DIR)/$(ATMOSPHERE_CPU_DIR)) \
|
||||
@@ -177,7 +147,7 @@ FIND_SOURCE_FILES=$(foreach dir,$1,$(filter-out $(notdir $(wildcard $(dir)/*.arc
|
||||
$(notdir $(wildcard $(dir)/*.os.*.$2)) \
|
||||
$(notdir $(wildcard $(dir)/.cpu.*.$2)), \
|
||||
$(notdir $(wildcard $(dir)/*.$2)))) \
|
||||
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES_EX,$(dir),arch,$(ATMOSPHERE_ARCH_NAME) $(ATMOSPHERE_SUB_ARCH_NAME),$2)) \
|
||||
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES,$(dir),arch,$(ATMOSPHERE_ARCH_NAME),$2)) \
|
||||
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES,$(dir),board,$(ATMOSPHERE_BOARD_NAME),$2)) \
|
||||
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES,$(dir),os,$(ATMOSPHERE_OS_NAME),$2)) \
|
||||
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES_EX,$(dir),cpu,$(ATMOSPHERE_CPU_NAME) $(ATMOSPHERE_CPU_EXTENSIONS),$2))
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace ams::pkg2 {
|
||||
|
||||
constexpr inline int PayloadCount = 3;
|
||||
|
||||
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x14 in Nintendo's code. */
|
||||
constexpr inline int CurrentBootloaderVersion = 0x10;
|
||||
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x13 in Nintendo's code. */
|
||||
constexpr inline int CurrentBootloaderVersion = 0xF;
|
||||
|
||||
struct Package2Meta {
|
||||
using Magic = util::FourCC<'P','K','2','1'>;
|
||||
|
||||
@@ -167,7 +167,6 @@ namespace ams::fuse {
|
||||
}
|
||||
|
||||
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
||||
TargetFirmware_13_2_1,
|
||||
TargetFirmware_12_0_2,
|
||||
TargetFirmware_11_0_0,
|
||||
TargetFirmware_10_0_0,
|
||||
|
||||
@@ -93,4 +93,3 @@
|
||||
|
||||
/* Deferred includes. */
|
||||
#include <mesosphere/kern_k_auto_object_impls.hpp>
|
||||
#include <mesosphere/kern_k_scheduler_impls.hpp>
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace ams::kern::arch::arm {
|
||||
PriorityLevel_Scheduler = 2,
|
||||
};
|
||||
private:
|
||||
static constinit inline u32 s_mask[cpu::NumCores];
|
||||
static inline u32 s_mask[cpu::NumCores];
|
||||
private:
|
||||
volatile GicDistributor *m_gicd;
|
||||
volatile GicCpuInterface *m_gicc;
|
||||
|
||||
@@ -279,7 +279,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
|
||||
/* Invalidate the entire tlb. */
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
cpu::InvalidateEntireTlbInnerShareable();
|
||||
cpu::InvalidateEntireTlb();
|
||||
|
||||
/* Copy data, if we should. */
|
||||
const u64 negative_block_size_for_mask = static_cast<u64>(-static_cast<s64>(block_size));
|
||||
@@ -350,6 +350,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
/* If we don't already have an L2 table, we need to make a new one. */
|
||||
if (!l1_entry->IsTable()) {
|
||||
KPhysicalAddress new_table = AllocateNewPageTable(allocator);
|
||||
ClearNewPageTable(new_table);
|
||||
*l1_entry = L1PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
@@ -360,12 +361,12 @@ namespace ams::kern::arch::arm64::init {
|
||||
if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && size >= L2ContiguousBlockSize) {
|
||||
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
||||
l2_entry[i] = L2PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, true);
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
virt_addr += L2BlockSize;
|
||||
phys_addr += L2BlockSize;
|
||||
size -= L2BlockSize;
|
||||
}
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -383,6 +384,7 @@ namespace ams::kern::arch::arm64::init {
|
||||
/* If we don't already have an L3 table, we need to make a new one. */
|
||||
if (!l2_entry->IsTable()) {
|
||||
KPhysicalAddress new_table = AllocateNewPageTable(allocator);
|
||||
ClearNewPageTable(new_table);
|
||||
*l2_entry = L2PageTableEntry(PageTableEntry::TableTag{}, new_table, attr.IsPrivilegedExecuteNever());
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
@@ -393,12 +395,12 @@ namespace ams::kern::arch::arm64::init {
|
||||
if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && size >= L3ContiguousBlockSize) {
|
||||
for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) {
|
||||
l3_entry[i] = L3PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, attr, PageTableEntry::SoftwareReservedBit_None, true);
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
virt_addr += L3BlockSize;
|
||||
phys_addr += L3BlockSize;
|
||||
size -= L3BlockSize;
|
||||
}
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
/* TODO: Different header for this? */
|
||||
#define AMS_KERN_NUM_SUPERVISOR_CALLS 0xC0
|
||||
|
||||
/* ams::kern::KThread, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp */
|
||||
#define THREAD_THREAD_CONTEXT 0xD0
|
||||
|
||||
/* 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 0x30
|
||||
#define THREAD_STACK_PARAMETERS_SVC_PERMISSION 0x00
|
||||
|
||||
@@ -52,19 +52,10 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
__asm__ __volatile__("dmb sy" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void DataMemoryBarrierInnerShareable() {
|
||||
__asm__ __volatile__("dmb ish" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void InstructionMemoryBarrier() {
|
||||
__asm__ __volatile__("isb" ::: "memory");
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void EnsureInstructionConsistencyInnerShareable() {
|
||||
DataSynchronizationBarrierInnerShareable();
|
||||
InstructionMemoryBarrier();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void EnsureInstructionConsistency() {
|
||||
DataSynchronizationBarrier();
|
||||
InstructionMemoryBarrier();
|
||||
@@ -182,6 +173,7 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
NOINLINE void SynchronizeAllCores();
|
||||
|
||||
/* Cache management helpers. */
|
||||
void ClearPageToZeroImpl(void *);
|
||||
void StoreEntireCacheForInit();
|
||||
void FlushEntireCacheForInit();
|
||||
|
||||
@@ -194,16 +186,10 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
|
||||
void InvalidateEntireInstructionCache();
|
||||
|
||||
ALWAYS_INLINE void ClearPageToZero(void * const page) {
|
||||
ALWAYS_INLINE void ClearPageToZero(void *page) {
|
||||
MESOSPHERE_ASSERT(util::IsAligned(reinterpret_cast<uintptr_t>(page), PageSize));
|
||||
MESOSPHERE_ASSERT(page != nullptr);
|
||||
|
||||
uintptr_t cur = reinterpret_cast<uintptr_t>(__builtin_assume_aligned(page, PageSize));
|
||||
const uintptr_t last = cur + PageSize - DataCacheLineSize;
|
||||
|
||||
for (/* ... */; cur <= last; cur += DataCacheLineSize) {
|
||||
__asm__ __volatile__("dc zva, %[cur]" :: [cur]"r"(cur) : "memory");
|
||||
}
|
||||
ClearPageToZeroImpl(page);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void InvalidateTlbByAsid(u32 asid) {
|
||||
@@ -223,11 +209,6 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
EnsureInstructionConsistency();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void InvalidateEntireTlbInnerShareable() {
|
||||
__asm__ __volatile__("tlbi vmalle1is" ::: "memory");
|
||||
EnsureInstructionConsistencyInnerShareable();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void InvalidateEntireTlbDataOnly() {
|
||||
__asm__ __volatile__("tlbi vmalle1is" ::: "memory");
|
||||
DataSynchronizationBarrier();
|
||||
|
||||
@@ -105,48 +105,35 @@ namespace ams::kern::arch::arm64 {
|
||||
Result UnbindLocal(s32 irq);
|
||||
Result ClearGlobal(s32 irq);
|
||||
Result ClearLocal(s32 irq);
|
||||
private:
|
||||
[[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledState() {
|
||||
public:
|
||||
static ALWAYS_INLINE u32 DisableInterrupts() {
|
||||
u64 intr_state;
|
||||
__asm__ __volatile__("mrs %[intr_state], daif\n"
|
||||
"ubfx %[intr_state], %[intr_state], #7, #1"
|
||||
__asm__ __volatile__("mrs %[intr_state], daif\n"
|
||||
"msr daifset, #2"
|
||||
: [intr_state]"=r"(intr_state)
|
||||
:: "memory");
|
||||
return intr_state;
|
||||
}
|
||||
public:
|
||||
static ALWAYS_INLINE void EnableInterrupts() {
|
||||
__asm__ __volatile__("msr daifclr, #2" ::: "memory");
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void DisableInterrupts() {
|
||||
__asm__ __volatile__("msr daifset, #2" ::: "memory");
|
||||
}
|
||||
|
||||
[[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledStateAndDisableInterrupts() {
|
||||
const auto intr_state = GetInterruptsEnabledState();
|
||||
DisableInterrupts();
|
||||
return intr_state;
|
||||
}
|
||||
|
||||
[[nodiscard]] static ALWAYS_INLINE u32 GetInterruptsEnabledStateAndEnableInterrupts() {
|
||||
const auto intr_state = GetInterruptsEnabledState();
|
||||
EnableInterrupts();
|
||||
static ALWAYS_INLINE u32 EnableInterrupts() {
|
||||
u64 intr_state;
|
||||
__asm__ __volatile__("mrs %[intr_state], daif\n"
|
||||
"msr daifclr, #2"
|
||||
: [intr_state]"=r"(intr_state)
|
||||
:: "memory");
|
||||
return intr_state;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void RestoreInterrupts(u32 intr_state) {
|
||||
u64 tmp;
|
||||
__asm__ __volatile__("mrs %[tmp], daif\n"
|
||||
"bfi %[tmp], %[intr_state], #7, #1\n"
|
||||
"msr daif, %[tmp]"
|
||||
: [tmp]"=&r"(tmp)
|
||||
: [intr_state]"r"(intr_state)
|
||||
: "memory");
|
||||
u64 cur_state;
|
||||
__asm__ __volatile__("mrs %[cur_state], daif" : [cur_state]"=r"(cur_state));
|
||||
__asm__ __volatile__("msr daif, %[intr_state]" :: [intr_state]"r"((cur_state & ~0x80ul) | (intr_state & 0x80)));
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE bool AreInterruptsEnabled() {
|
||||
return GetInterruptsEnabledState() == 0;
|
||||
u64 intr_state;
|
||||
__asm__ __volatile__("mrs %[intr_state], daif" : [intr_state]"=r"(intr_state));
|
||||
return (intr_state & 0x80) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -219,27 +219,27 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
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);
|
||||
|
||||
static ALWAYS_INLINE void PteDataSynchronizationBarrier() {
|
||||
static void PteDataSynchronizationBarrier() {
|
||||
cpu::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void ClearPageTable(KVirtualAddress table) {
|
||||
static void ClearPageTable(KVirtualAddress table) {
|
||||
cpu::ClearPageToZero(GetVoidPointer(table));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void OnTableUpdated() const {
|
||||
void OnTableUpdated() const {
|
||||
cpu::InvalidateTlbByAsid(m_asid);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void OnKernelTableUpdated() const {
|
||||
void OnKernelTableUpdated() const {
|
||||
cpu::InvalidateEntireTlbDataOnly();
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void OnKernelTableSinglePageUpdated(KProcessAddress virt_addr) const {
|
||||
void OnKernelTableSinglePageUpdated(KProcessAddress virt_addr) const {
|
||||
cpu::InvalidateTlbByVaDataOnly(virt_addr);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void NoteUpdated() const {
|
||||
void NoteUpdated() const {
|
||||
cpu::DataSynchronizationBarrier();
|
||||
|
||||
if (this->IsKernel()) {
|
||||
@@ -249,7 +249,7 @@ namespace ams::kern::arch::arm64 {
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void NoteSingleKernelPageUpdated(KProcessAddress virt_addr) const {
|
||||
void NoteSingleKernelPageUpdated(KProcessAddress virt_addr) const {
|
||||
MESOSPHERE_ASSERT(this->IsKernel());
|
||||
|
||||
cpu::DataSynchronizationBarrier();
|
||||
|
||||
@@ -45,7 +45,6 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
/* Select L1 cache. */
|
||||
cpu::SetCsselrEl1(0);
|
||||
cpu::InstructionMemoryBarrier();
|
||||
|
||||
/* Check that the L1 cache is not direct-mapped. */
|
||||
return cpu::CacheSizeIdRegisterAccessor().GetAssociativity() != 0;
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
/* of the right side, and so this does not actually cost any space. */
|
||||
#define MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST
|
||||
|
||||
/* NOTE: This enables usage of KDebug handles as parameter for svc::GetInfo */
|
||||
/* calls which require a process parameter. This enables a debugger to obtain */
|
||||
/* address space/layout information, for example. However, it changes abi, and so */
|
||||
/* this define allows toggling the extension. */
|
||||
#define MESOSPHERE_ENABLE_GET_INFO_OF_DEBUG_PROCESS
|
||||
|
||||
/* NOTE: This uses currently-reserved bits inside the MapRange capability */
|
||||
/* in order to support large physical addresses (40-bit instead of 36). */
|
||||
/* This is toggleable in order to disable it if N ever uses those bits. */
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace ams::kern {
|
||||
return m_slab_heap->Allocate(m_page_allocator);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void Free(T *t) const {
|
||||
void Free(T *t) const {
|
||||
m_slab_heap->Free(t);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -62,7 +62,8 @@ namespace ams::kern {
|
||||
KThread *m_idle_thread;
|
||||
util::Atomic<KThread *> m_current_thread;
|
||||
public:
|
||||
constexpr KScheduler() : m_state(), m_is_active(false), m_core_id(0), m_last_context_switch_time(0), m_idle_thread(nullptr), m_current_thread(nullptr) {
|
||||
constexpr KScheduler() : m_state(), m_is_active(false), m_core_id(0), m_last_context_switch_time(0), m_idle_thread(nullptr), m_current_thread(nullptr)
|
||||
{
|
||||
m_state.needs_scheduling = true;
|
||||
m_state.interrupt_task_runnable = false;
|
||||
m_state.should_count_idle = false;
|
||||
@@ -210,6 +211,18 @@ namespace ams::kern {
|
||||
static consteval bool ValidateAssemblyOffsets();
|
||||
};
|
||||
|
||||
consteval bool KScheduler::ValidateAssemblyOffsets() {
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.needs_scheduling) == KSCHEDULER_NEEDS_SCHEDULING);
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.interrupt_task_runnable) == KSCHEDULER_INTERRUPT_TASK_RUNNABLE);
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.highest_priority_thread) == KSCHEDULER_HIGHEST_PRIORITY_THREAD);
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.idle_thread_stack) == KSCHEDULER_IDLE_THREAD_STACK);
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.prev_thread) == KSCHEDULER_PREVIOUS_THREAD);
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.interrupt_task_manager) == KSCHEDULER_INTERRUPT_TASK_MANAGER);
|
||||
|
||||
return true;
|
||||
}
|
||||
static_assert(KScheduler::ValidateAssemblyOffsets());
|
||||
|
||||
class KScopedSchedulerLock : KScopedLock<KScheduler::LockType> {
|
||||
public:
|
||||
explicit ALWAYS_INLINE KScopedSchedulerLock() : KScopedLock(KScheduler::s_scheduler_lock) { /* ... */ }
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <mesosphere/kern_common.hpp>
|
||||
#include <mesosphere/kern_k_scheduler.hpp>
|
||||
#include <mesosphere/kern_select_interrupt_manager.hpp>
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
/* NOTE: This header is included after all main headers. */
|
||||
consteval bool KScheduler::ValidateAssemblyOffsets() {
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.needs_scheduling) == KSCHEDULER_NEEDS_SCHEDULING);
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.interrupt_task_runnable) == KSCHEDULER_INTERRUPT_TASK_RUNNABLE);
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.highest_priority_thread) == KSCHEDULER_HIGHEST_PRIORITY_THREAD);
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.idle_thread_stack) == KSCHEDULER_IDLE_THREAD_STACK);
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.prev_thread) == KSCHEDULER_PREVIOUS_THREAD);
|
||||
static_assert(AMS_OFFSETOF(KScheduler, m_state.interrupt_task_manager) == KSCHEDULER_INTERRUPT_TASK_MANAGER);
|
||||
|
||||
return true;
|
||||
}
|
||||
static_assert(KScheduler::ValidateAssemblyOffsets());
|
||||
|
||||
ALWAYS_INLINE void KScheduler::RescheduleOtherCores(u64 cores_needing_scheduling) {
|
||||
if (const u64 core_mask = cores_needing_scheduling & ~(1ul << m_core_id); core_mask != 0) {
|
||||
cpu::DataSynchronizationBarrier();
|
||||
Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_Scheduler, core_mask);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -74,9 +74,6 @@ namespace ams::kern {
|
||||
|
||||
/* Release an instance of the lock. */
|
||||
if ((--m_lock_count) == 0) {
|
||||
/* Perform a memory barrier here. */
|
||||
cpu::DataMemoryBarrierInnerShareable();
|
||||
|
||||
/* We're no longer going to hold the lock. Take note of what cores need scheduling. */
|
||||
const u64 cores_needing_scheduling = SchedulerType::UpdateHighestPriorityThreads();
|
||||
|
||||
|
||||
@@ -405,6 +405,8 @@ namespace ams::kern {
|
||||
constexpr ThreadState GetState() const { return static_cast<ThreadState>(m_thread_state & ThreadState_Mask); }
|
||||
constexpr ThreadState GetRawState() const { return m_thread_state; }
|
||||
|
||||
NOINLINE KThreadContext *GetContextForSchedulerLoop();
|
||||
|
||||
constexpr uintptr_t GetConditionVariableKey() const { return m_condvar_key; }
|
||||
constexpr uintptr_t GetAddressArbiterKey() const { return m_condvar_key; }
|
||||
|
||||
@@ -622,7 +624,9 @@ namespace ams::kern {
|
||||
void OnTimer();
|
||||
void DoWorkerTaskImpl();
|
||||
public:
|
||||
static consteval bool IsKThreadStructurallyValid();
|
||||
static constexpr bool IsConditionVariableThreadTreeValid() {
|
||||
return ConditionVariableThreadTreeTraits::IsValid();
|
||||
}
|
||||
|
||||
static KThread *GetThreadFromId(u64 thread_id);
|
||||
static Result GetThreadList(s32 *out_num_threads, ams::kern::svc::KUserPointer<u64 *> out_thread_ids, s32 max_out_count);
|
||||
@@ -630,18 +634,7 @@ namespace ams::kern {
|
||||
using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
|
||||
};
|
||||
static_assert(alignof(KThread) == 0x10);
|
||||
|
||||
consteval bool KThread::IsKThreadStructurallyValid() {
|
||||
/* Check that the condition variable tree is valid. */
|
||||
static_assert(ConditionVariableThreadTreeTraits::IsValid());
|
||||
|
||||
/* Check that the assembly offsets are valid. */
|
||||
static_assert(AMS_OFFSETOF(KThread, m_thread_context) == THREAD_THREAD_CONTEXT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(KThread::IsKThreadStructurallyValid());
|
||||
static_assert(KThread::IsConditionVariableThreadTreeValid());
|
||||
|
||||
class KScopedDisableDispatch {
|
||||
public:
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace ams::kern {
|
||||
private:
|
||||
u32 m_prev_intr_state;
|
||||
public:
|
||||
ALWAYS_INLINE KScopedInterruptDisable() : m_prev_intr_state(KInterruptManager::GetInterruptsEnabledStateAndDisableInterrupts()) { /* ... */ }
|
||||
ALWAYS_INLINE KScopedInterruptDisable() : m_prev_intr_state(KInterruptManager::DisableInterrupts()) { /* ... */ }
|
||||
ALWAYS_INLINE ~KScopedInterruptDisable() { KInterruptManager::RestoreInterrupts(m_prev_intr_state); }
|
||||
};
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace ams::kern {
|
||||
private:
|
||||
u32 m_prev_intr_state;
|
||||
public:
|
||||
ALWAYS_INLINE KScopedInterruptEnable() : m_prev_intr_state(KInterruptManager::GetInterruptsEnabledStateAndEnableInterrupts()) { /* ... */ }
|
||||
ALWAYS_INLINE KScopedInterruptEnable() : m_prev_intr_state(KInterruptManager::EnableInterrupts()) { /* ... */ }
|
||||
ALWAYS_INLINE ~KScopedInterruptEnable() { KInterruptManager::RestoreInterrupts(m_prev_intr_state); }
|
||||
};
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
|
||||
class KPerformanceCounterInterruptHandler : public KInterruptHandler {
|
||||
private:
|
||||
static constinit inline KLightLock s_lock;
|
||||
static inline KLightLock s_lock;
|
||||
private:
|
||||
u64 m_counter;
|
||||
s32 m_which;
|
||||
@@ -76,7 +76,7 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
} else {
|
||||
m_counter = cpu::GetPerformanceCounter(m_which);
|
||||
}
|
||||
DataMemoryBarrierInnerShareable();
|
||||
DataMemoryBarrier();
|
||||
m_done = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -61,3 +61,139 @@ _ZN3ams4kern4arch5arm643cpu23SynchronizeAllCoresImplEPii:
|
||||
5:
|
||||
stlr wzr, [x0]
|
||||
ret
|
||||
|
||||
|
||||
/* ams::kern::arch::arm64::cpu::ClearPageToZero(void *) */
|
||||
.section .text._ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv, "ax", %progbits
|
||||
.global _ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv
|
||||
.type _ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv, %function
|
||||
_ZN3ams4kern4arch5arm643cpu19ClearPageToZeroImplEPv:
|
||||
/* Efficiently clear the page using dc zva. */
|
||||
dc zva, x0
|
||||
add x8, x0, #0x040
|
||||
dc zva, x8
|
||||
add x8, x0, #0x080
|
||||
dc zva, x8
|
||||
add x8, x0, #0x0c0
|
||||
dc zva, x8
|
||||
add x8, x0, #0x100
|
||||
dc zva, x8
|
||||
add x8, x0, #0x140
|
||||
dc zva, x8
|
||||
add x8, x0, #0x180
|
||||
dc zva, x8
|
||||
add x8, x0, #0x1c0
|
||||
dc zva, x8
|
||||
add x8, x0, #0x200
|
||||
dc zva, x8
|
||||
add x8, x0, #0x240
|
||||
dc zva, x8
|
||||
add x8, x0, #0x280
|
||||
dc zva, x8
|
||||
add x8, x0, #0x2c0
|
||||
dc zva, x8
|
||||
add x8, x0, #0x300
|
||||
dc zva, x8
|
||||
add x8, x0, #0x340
|
||||
dc zva, x8
|
||||
add x8, x0, #0x380
|
||||
dc zva, x8
|
||||
add x8, x0, #0x3c0
|
||||
dc zva, x8
|
||||
add x8, x0, #0x400
|
||||
dc zva, x8
|
||||
add x8, x0, #0x440
|
||||
dc zva, x8
|
||||
add x8, x0, #0x480
|
||||
dc zva, x8
|
||||
add x8, x0, #0x4c0
|
||||
dc zva, x8
|
||||
add x8, x0, #0x500
|
||||
dc zva, x8
|
||||
add x8, x0, #0x540
|
||||
dc zva, x8
|
||||
add x8, x0, #0x580
|
||||
dc zva, x8
|
||||
add x8, x0, #0x5c0
|
||||
dc zva, x8
|
||||
add x8, x0, #0x600
|
||||
dc zva, x8
|
||||
add x8, x0, #0x640
|
||||
dc zva, x8
|
||||
add x8, x0, #0x680
|
||||
dc zva, x8
|
||||
add x8, x0, #0x6c0
|
||||
dc zva, x8
|
||||
add x8, x0, #0x700
|
||||
dc zva, x8
|
||||
add x8, x0, #0x740
|
||||
dc zva, x8
|
||||
add x8, x0, #0x780
|
||||
dc zva, x8
|
||||
add x8, x0, #0x7c0
|
||||
dc zva, x8
|
||||
add x8, x0, #0x800
|
||||
dc zva, x8
|
||||
add x8, x0, #0x840
|
||||
dc zva, x8
|
||||
add x8, x0, #0x880
|
||||
dc zva, x8
|
||||
add x8, x0, #0x8c0
|
||||
dc zva, x8
|
||||
add x8, x0, #0x900
|
||||
dc zva, x8
|
||||
add x8, x0, #0x940
|
||||
dc zva, x8
|
||||
add x8, x0, #0x980
|
||||
dc zva, x8
|
||||
add x8, x0, #0x9c0
|
||||
dc zva, x8
|
||||
add x8, x0, #0xa00
|
||||
dc zva, x8
|
||||
add x8, x0, #0xa40
|
||||
dc zva, x8
|
||||
add x8, x0, #0xa80
|
||||
dc zva, x8
|
||||
add x8, x0, #0xac0
|
||||
dc zva, x8
|
||||
add x8, x0, #0xb00
|
||||
dc zva, x8
|
||||
add x8, x0, #0xb40
|
||||
dc zva, x8
|
||||
add x8, x0, #0xb80
|
||||
dc zva, x8
|
||||
add x8, x0, #0xbc0
|
||||
dc zva, x8
|
||||
add x8, x0, #0xc00
|
||||
dc zva, x8
|
||||
add x8, x0, #0xc40
|
||||
dc zva, x8
|
||||
add x8, x0, #0xc80
|
||||
dc zva, x8
|
||||
add x8, x0, #0xcc0
|
||||
dc zva, x8
|
||||
add x8, x0, #0xd00
|
||||
dc zva, x8
|
||||
add x8, x0, #0xd40
|
||||
dc zva, x8
|
||||
add x8, x0, #0xd80
|
||||
dc zva, x8
|
||||
add x8, x0, #0xdc0
|
||||
dc zva, x8
|
||||
add x8, x0, #0xe00
|
||||
dc zva, x8
|
||||
add x8, x0, #0xe40
|
||||
dc zva, x8
|
||||
add x8, x0, #0xe80
|
||||
dc zva, x8
|
||||
add x8, x0, #0xec0
|
||||
dc zva, x8
|
||||
add x8, x0, #0xf00
|
||||
dc zva, x8
|
||||
add x8, x0, #0xf40
|
||||
dc zva, x8
|
||||
add x8, x0, #0xf80
|
||||
dc zva, x8
|
||||
add x8, x0, #0xfc0
|
||||
dc zva, x8
|
||||
ret
|
||||
@@ -225,7 +225,7 @@ namespace ams::kern::arch::arm64 {
|
||||
if (AMS_UNLIKELY(GetCurrentThread().IsSingleStep())) {
|
||||
GetCurrentThread().ClearSingleStep();
|
||||
cpu::MonitorDebugSystemControlRegisterAccessor().SetSoftwareStep(false).Store();
|
||||
cpu::InstructionMemoryBarrier();
|
||||
cpu::EnsureInstructionConsistency();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace ams::kern::arch::arm64 {
|
||||
if (user_mode) {
|
||||
KThread *cur_thread = GetCurrentThreadPointer();
|
||||
if (cur_thread->IsTerminationRequested()) {
|
||||
EnableInterrupts();
|
||||
KScopedInterruptEnable ei;
|
||||
cur_thread->Exit();
|
||||
}
|
||||
}
|
||||
@@ -212,14 +212,13 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
|
||||
|
||||
KScopedInterruptDisable di;
|
||||
|
||||
if (KInterruptController::IsGlobal(irq)) {
|
||||
KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(this->GetGlobalInterruptLock());
|
||||
return this->BindGlobal(handler, irq, core_id, priority, manual_clear, level);
|
||||
} else {
|
||||
MESOSPHERE_ASSERT(core_id == GetCurrentCoreId());
|
||||
|
||||
KScopedInterruptDisable di;
|
||||
return this->BindLocal(handler, irq, priority, manual_clear);
|
||||
}
|
||||
}
|
||||
@@ -229,16 +228,13 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
|
||||
|
||||
KScopedInterruptDisable di;
|
||||
|
||||
if (KInterruptController::IsGlobal(irq)) {
|
||||
KScopedInterruptDisable di;
|
||||
|
||||
KScopedSpinLock lk(this->GetGlobalInterruptLock());
|
||||
return this->UnbindGlobal(irq);
|
||||
} else {
|
||||
MESOSPHERE_ASSERT(core_id == GetCurrentCoreId());
|
||||
|
||||
KScopedInterruptDisable di;
|
||||
return this->UnbindLocal(irq);
|
||||
}
|
||||
}
|
||||
@@ -248,15 +244,13 @@ namespace ams::kern::arch::arm64 {
|
||||
|
||||
R_UNLESS(KInterruptController::IsGlobal(irq) || KInterruptController::IsLocal(irq), svc::ResultOutOfRange());
|
||||
|
||||
KScopedInterruptDisable di;
|
||||
|
||||
if (KInterruptController::IsGlobal(irq)) {
|
||||
KScopedInterruptDisable di;
|
||||
KScopedSpinLock lk(this->GetGlobalInterruptLock());
|
||||
return this->ClearGlobal(irq);
|
||||
} else {
|
||||
MESOSPHERE_ASSERT(core_id == GetCurrentCoreId());
|
||||
|
||||
KScopedInterruptDisable di;
|
||||
return this->ClearLocal(irq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,10 +169,10 @@ namespace ams::kern::arch::arm64 {
|
||||
m_manager = std::addressof(Kernel::GetSystemPageTableManager());
|
||||
|
||||
/* Allocate a page for ttbr. */
|
||||
/* NOTE: It is a postcondition of page table manager allocation that the page is all-zero. */
|
||||
const u64 asid_tag = (static_cast<u64>(m_asid) << 48ul);
|
||||
const KVirtualAddress page = m_manager->Allocate();
|
||||
MESOSPHERE_ASSERT(page != Null<KVirtualAddress>);
|
||||
cpu::ClearPageToZero(GetVoidPointer(page));
|
||||
m_ttbr = GetInteger(KPageTableBase::GetLinearMappedPhysicalAddress(page)) | asid_tag;
|
||||
|
||||
/* Initialize the base page table. */
|
||||
@@ -1058,7 +1058,7 @@ namespace ams::kern::arch::arm64 {
|
||||
auto sw_reserved_bits = PageTableEntry::EncodeSoftwareReservedBits(head_entry->IsHeadMergeDisabled(), head_entry->IsHeadAndBodyMergeDisabled(), tail_entry->IsTailMergeDisabled());
|
||||
|
||||
/* Merge! */
|
||||
/* NOTE: As of 13.1.0, Nintendo does not do: PteDataSynchronizationBarrier(); */
|
||||
PteDataSynchronizationBarrier();
|
||||
*l1_entry = L1PageTableEntry(PageTableEntry::BlockTag{}, phys_addr, PageTableEntry(entry_template), sw_reserved_bits, false);
|
||||
|
||||
/* Note that we updated. */
|
||||
|
||||
@@ -28,7 +28,7 @@ _ZN3ams4kern3svc25CallReturnFromException64Ev:
|
||||
stp x20, x21, [sp, #(EXCEPTION_CONTEXT_X20_X21)]
|
||||
stp x22, x23, [sp, #(EXCEPTION_CONTEXT_X22_X23)]
|
||||
stp x24, x25, [sp, #(EXCEPTION_CONTEXT_X24_X25)]
|
||||
stp x26, x27, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
|
||||
stp x26, x26, [sp, #(EXCEPTION_CONTEXT_X26_X27)]
|
||||
stp x28, x29, [sp, #(EXCEPTION_CONTEXT_X28_X29)]
|
||||
|
||||
/* Call ams::kern::arch::arm64::ReturnFromException(result). */
|
||||
|
||||
@@ -50,6 +50,10 @@ _ZN3ams4kern3svc26CallSendSyncRequestLight64Ev:
|
||||
.global _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev
|
||||
.type _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev, %function
|
||||
_ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev:
|
||||
/* Load x4-x7 from where the svc handler stores them. */
|
||||
ldp x4, x5, [sp, #(8 * 0)]
|
||||
ldp x6, x7, [sp, #(8 * 2)]
|
||||
|
||||
/* Allocate space for the light ipc data. */
|
||||
sub sp, sp, #(4 * 8)
|
||||
|
||||
@@ -74,8 +78,13 @@ _ZN3ams4kern3svc32CallSendSyncRequestLight64From32Ev:
|
||||
/* Free the stack space for the light ipc data. */
|
||||
add sp, sp, #(4 * 8)
|
||||
|
||||
/* Save x4-x7 to where the svc handler stores them. */
|
||||
stp x4, x5, [sp, #(8 * 0)]
|
||||
stp x6, x7, [sp, #(8 * 2)]
|
||||
|
||||
ret
|
||||
|
||||
|
||||
/* ams::kern::svc::CallReplyAndReceiveLight64() */
|
||||
.section .text._ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev, "ax", %progbits
|
||||
.global _ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev
|
||||
@@ -112,6 +121,10 @@ _ZN3ams4kern3svc26CallReplyAndReceiveLight64Ev:
|
||||
.global _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev
|
||||
.type _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev, %function
|
||||
_ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev:
|
||||
/* Load x4-x7 from where the svc handler stores them. */
|
||||
ldp x4, x5, [sp, #(8 * 0)]
|
||||
ldp x6, x7, [sp, #(8 * 2)]
|
||||
|
||||
/* Allocate space for the light ipc data. */
|
||||
sub sp, sp, #(4 * 8)
|
||||
|
||||
@@ -136,4 +149,8 @@ _ZN3ams4kern3svc32CallReplyAndReceiveLight64From32Ev:
|
||||
/* Free the stack space for the light ipc data. */
|
||||
add sp, sp, #(4 * 8)
|
||||
|
||||
/* Save x4-x7 to where the svc handler stores them. */
|
||||
stp x4, x5, [sp, #(8 * 0)]
|
||||
stp x6, x7, [sp, #(8 * 2)]
|
||||
|
||||
ret
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace ams::kern::svc {
|
||||
|
||||
/* Set omit-frame-pointer to prevent GCC from emitting MOV X29, SP instructions. */
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("-O3")
|
||||
#pragma GCC optimize ("-O2")
|
||||
#pragma GCC optimize ("omit-frame-pointer")
|
||||
|
||||
AMS_SVC_FOREACH_KERN_DEFINITION(DECLARE_SVC_STRUCT, _)
|
||||
|
||||
@@ -114,7 +114,6 @@ namespace ams::kern::board::nintendo::nx {
|
||||
ams::svc::DeviceName_Hda,
|
||||
ams::svc::DeviceName_Isp2,
|
||||
ams::svc::DeviceName_Sata,
|
||||
ams::svc::DeviceName_Vi,
|
||||
ams::svc::DeviceName_XusbHost,
|
||||
ams::svc::DeviceName_XusbDev,
|
||||
ams::svc::DeviceName_Tsec,
|
||||
@@ -549,11 +548,11 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
/* Print the interrupt. */
|
||||
{
|
||||
constexpr auto GetBits = [](u32 value, size_t ofs, size_t count) ALWAYS_INLINE_LAMBDA {
|
||||
constexpr auto GetBits = [] ALWAYS_INLINE_LAMBDA (u32 value, size_t ofs, size_t count) {
|
||||
return (value >> ofs) & ((1u << count) - 1);
|
||||
};
|
||||
|
||||
constexpr auto GetBit = [GetBits](u32 value, size_t ofs) ALWAYS_INLINE_LAMBDA {
|
||||
constexpr auto GetBit = [GetBits] ALWAYS_INLINE_LAMBDA (u32 value, size_t ofs) {
|
||||
return (value >> ofs) & 1u;
|
||||
};
|
||||
|
||||
@@ -657,8 +656,9 @@ namespace ams::kern::board::nintendo::nx {
|
||||
MESOSPHERE_ASSERT(IsValidPhysicalAddress(table_phys_addr));
|
||||
Kernel::GetSystemPageTableManager().Open(table_virt_addr, 1);
|
||||
|
||||
/* Save the page. Note that it is a pre-condition that the page is cleared, when allocated from the system page table manager. */
|
||||
/* Clear the page and save it. */
|
||||
/* NOTE: Nintendo does not check the result of StoreDataCache. */
|
||||
cpu::ClearPageToZero(GetVoidPointer(table_virt_addr));
|
||||
cpu::StoreDataCache(GetVoidPointer(table_virt_addr), PageDirectorySize);
|
||||
g_reserved_table_phys_addr = table_phys_addr;
|
||||
|
||||
|
||||
@@ -341,9 +341,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
/* Restore pmu registers. */
|
||||
cpu::SetPmUserEnrEl0(0);
|
||||
cpu::PerformanceMonitorsControlRegisterAccessor(0).SetEventCounterReset(true).SetCycleCounterReset(true).Store();
|
||||
cpu::EnsureInstructionConsistency();
|
||||
|
||||
cpu::PerformanceMonitorsControlRegisterAccessor().SetEventCounterReset(true).SetCycleCounterReset(true).Store();
|
||||
cpu::SetPmOvsClrEl0(static_cast<u64>(static_cast<u32>(~u32())));
|
||||
cpu::SetPmIntEnClrEl1(static_cast<u64>(static_cast<u32>(~u32())));
|
||||
cpu::SetPmCntEnClrEl0(static_cast<u64>(static_cast<u32>(~u32())));
|
||||
|
||||
@@ -312,7 +312,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
size_t KSystemControl::Init::GetApplicationPoolSize() {
|
||||
/* Get the base pool size. */
|
||||
const size_t base_pool_size = []() ALWAYS_INLINE_LAMBDA -> size_t {
|
||||
const size_t base_pool_size = [] ALWAYS_INLINE_LAMBDA () -> size_t {
|
||||
switch (GetMemoryArrangeForInit()) {
|
||||
case smc::MemoryArrangement_4GB:
|
||||
default:
|
||||
@@ -336,7 +336,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
size_t KSystemControl::Init::GetAppletPoolSize() {
|
||||
/* Get the base pool size. */
|
||||
const size_t base_pool_size = []() ALWAYS_INLINE_LAMBDA -> size_t {
|
||||
const size_t base_pool_size = [] ALWAYS_INLINE_LAMBDA () -> size_t {
|
||||
switch (GetMemoryArrangeForInit()) {
|
||||
case smc::MemoryArrangement_4GB:
|
||||
default:
|
||||
@@ -490,7 +490,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
|
||||
if (AMS_LIKELY(s_initialized_random_generator)) {
|
||||
return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return s_random_generator.GenerateRandomU64(); });
|
||||
return KSystemControlBase::GenerateUniformRange(min, max, [] ALWAYS_INLINE_LAMBDA () -> u64 { return s_random_generator.GenerateRandomU64(); });
|
||||
} else {
|
||||
return KSystemControlBase::GenerateUniformRange(min, max, GenerateRandomU64FromSmc);
|
||||
}
|
||||
@@ -680,4 +680,4 @@ namespace ams::kern::board::nintendo::nx {
|
||||
Kernel::GetMemoryManager().Close(KPageTable::GetHeapPhysicalAddress(address), size / PageSize);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -250,7 +250,7 @@ namespace ams::kern {
|
||||
{
|
||||
const u32 has_waiter_flag = 1;
|
||||
WriteToUser(key, std::addressof(has_waiter_flag));
|
||||
cpu::DataMemoryBarrierInnerShareable();
|
||||
cpu::DataMemoryBarrier();
|
||||
}
|
||||
|
||||
/* Write the value to userspace. */
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace ams::kern {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const std::pair<KMemoryState, const char *> MemoryStateNames[] = {
|
||||
constexpr std::tuple<KMemoryState, const char *> MemoryStateNames[] = {
|
||||
{KMemoryState_Free , "----- Free -----"},
|
||||
{KMemoryState_Io , "Io "},
|
||||
{KMemoryState_Static , "Static "},
|
||||
@@ -41,7 +41,6 @@ namespace ams::kern {
|
||||
{KMemoryState_Kernel , "Kernel "},
|
||||
{KMemoryState_GeneratedCode , "GeneratedCode "},
|
||||
{KMemoryState_CodeOut , "CodeOut "},
|
||||
{KMemoryState_Coverage , "Coverage "},
|
||||
};
|
||||
|
||||
constexpr const char *GetMemoryStateName(KMemoryState state) {
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace ams::kern {
|
||||
static_assert(KMemoryManager::Pool_Secure == KMemoryManager::Pool_System);
|
||||
|
||||
/* Get Secure pool size. */
|
||||
const size_t secure_pool_size = [](auto target_firmware) ALWAYS_INLINE_LAMBDA -> size_t {
|
||||
const size_t secure_pool_size = [] ALWAYS_INLINE_LAMBDA (auto target_firmware) -> size_t {
|
||||
constexpr size_t LegacySecureKernelSize = 8_MB; /* KPageBuffer pages, other small kernel allocations. */
|
||||
constexpr size_t LegacySecureMiscSize = 1_MB; /* Miscellaneous pages for secure process mapping. */
|
||||
constexpr size_t LegacySecureHeapSize = 24_MB; /* Heap pages for secure process mapping (fs). */
|
||||
@@ -274,4 +274,4 @@ namespace ams::kern {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2398,7 +2398,7 @@ namespace ams::kern {
|
||||
size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1));
|
||||
size_t tot_size = cur_size;
|
||||
|
||||
auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result {
|
||||
auto PerformCopy = [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
/* Ensure the address is linear mapped. */
|
||||
R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
@@ -2484,7 +2484,7 @@ namespace ams::kern {
|
||||
size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1));
|
||||
size_t tot_size = cur_size;
|
||||
|
||||
auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result {
|
||||
auto PerformCopy = [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
/* Ensure the address is linear mapped. */
|
||||
R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
@@ -2943,7 +2943,7 @@ namespace ams::kern {
|
||||
size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1));
|
||||
size_t tot_size = cur_size;
|
||||
|
||||
auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result {
|
||||
auto PerformCopy = [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
/* Ensure the address is linear mapped. */
|
||||
R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
@@ -3023,7 +3023,7 @@ namespace ams::kern {
|
||||
size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1));
|
||||
size_t tot_size = cur_size;
|
||||
|
||||
auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result {
|
||||
auto PerformCopy = [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
/* Ensure the address is linear mapped. */
|
||||
R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
@@ -3092,7 +3092,7 @@ namespace ams::kern {
|
||||
size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1));
|
||||
size_t tot_size = cur_size;
|
||||
|
||||
auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result {
|
||||
auto PerformCopy = [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
/* Ensure the address is linear mapped. */
|
||||
R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
@@ -3172,7 +3172,7 @@ namespace ams::kern {
|
||||
size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1));
|
||||
size_t tot_size = cur_size;
|
||||
|
||||
auto PerformCopy = [&]() ALWAYS_INLINE_LAMBDA -> Result {
|
||||
auto PerformCopy = [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
/* Ensure the address is linear mapped. */
|
||||
R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
|
||||
@@ -893,7 +893,7 @@ namespace ams::kern {
|
||||
size_t KProcess::GetTotalUserPhysicalMemorySize() const {
|
||||
/* Get the amount of free and used size. */
|
||||
const size_t free_size = m_resource_limit->GetFreeValue(ams::svc::LimitableResource_PhysicalMemoryMax);
|
||||
const size_t used_size = this->GetUsedUserPhysicalMemorySize();
|
||||
const size_t used_size = this->GetUsedNonSystemUserPhysicalMemorySize();
|
||||
const size_t max_size = m_max_process_memory;
|
||||
|
||||
if (used_size + free_size > max_size) {
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("-O3")
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("-O3")
|
||||
|
||||
bool KScheduler::s_scheduler_update_needed;
|
||||
KScheduler::LockType KScheduler::s_scheduler_lock;
|
||||
KSchedulerPriorityQueue KScheduler::s_priority_queue;
|
||||
@@ -79,6 +79,13 @@ namespace ams::kern {
|
||||
RescheduleCurrentCore();
|
||||
}
|
||||
|
||||
void KScheduler::RescheduleOtherCores(u64 cores_needing_scheduling) {
|
||||
if (const u64 core_mask = cores_needing_scheduling & ~(1ul << m_core_id); core_mask != 0) {
|
||||
cpu::DataSynchronizationBarrier();
|
||||
Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_Scheduler, core_mask);
|
||||
}
|
||||
}
|
||||
|
||||
u64 KScheduler::UpdateHighestPriorityThread(KThread *highest_thread) {
|
||||
if (KThread *prev_highest_thread = m_state.highest_priority_thread; AMS_LIKELY(prev_highest_thread != highest_thread)) {
|
||||
if (AMS_LIKELY(prev_highest_thread != nullptr)) {
|
||||
@@ -247,17 +254,6 @@ namespace ams::kern {
|
||||
|
||||
MESOSPHERE_KTRACE_THREAD_SWITCH(next_thread);
|
||||
|
||||
#if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP)
|
||||
/* Ensure the single-step bit in mdscr reflects the correct single-step state for the new thread. */
|
||||
/* NOTE: Per ARM docs, changing the single-step bit requires a "context synchronization event" to */
|
||||
/* be sure that our new configuration takes. However, there are three types of synchronization event: */
|
||||
/* Taking an exception, returning from an exception, and ISB. The single-step bit change only matters */
|
||||
/* in EL0...which implies a return-from-exception has occurred since we set the bit. Thus, forcing */
|
||||
/* an ISB is unnecessary, and we can modify the register safely and be confident it will affect the next */
|
||||
/* userland instruction executed. */
|
||||
cpu::MonitorDebugSystemControlRegisterAccessor().SetSoftwareStep(next_thread->IsSingleStep()).Store();
|
||||
#endif
|
||||
|
||||
/* Switch the current process, if we're switching processes. */
|
||||
if (KProcess *next_process = next_thread->GetOwnerProcess(); next_process != cur_process) {
|
||||
KProcess::Switch(cur_process, next_process);
|
||||
@@ -598,6 +594,6 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#pragma GCC pop_options
|
||||
|
||||
#pragma GCC pop_options
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("-O3")
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("-O3")
|
||||
|
||||
namespace ipc {
|
||||
|
||||
using MessageBuffer = ams::svc::ipc::MessageBuffer;
|
||||
@@ -1385,6 +1385,8 @@ namespace ams::kern {
|
||||
this->NotifyAvailable(svc::ResultSessionClosed());
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
void KServerSession::Dump() {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
|
||||
@@ -1418,5 +1420,3 @@ namespace ams::kern {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace ams::kern {
|
||||
s_initialized_random_generator = true;
|
||||
}
|
||||
|
||||
return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return s_random_generator.GenerateRandomU64(); });
|
||||
return KSystemControlBase::GenerateUniformRange(min, max, [] ALWAYS_INLINE_LAMBDA () -> u64 { return s_random_generator.GenerateRandomU64(); });
|
||||
}
|
||||
|
||||
/* System Initialization. */
|
||||
@@ -194,7 +194,7 @@ namespace ams::kern {
|
||||
KScopedInterruptDisable intr_disable;
|
||||
KScopedSpinLock lk(s_random_lock);
|
||||
|
||||
return KSystemControlBase::GenerateUniformRange(min, max, []() ALWAYS_INLINE_LAMBDA -> u64 { return s_random_generator.GenerateRandomU64(); });
|
||||
return KSystemControlBase::GenerateUniformRange(min, max, [] ALWAYS_INLINE_LAMBDA () -> u64 { return s_random_generator.GenerateRandomU64(); });
|
||||
}
|
||||
|
||||
u64 KSystemControlBase::GenerateRandomU64() {
|
||||
@@ -292,4 +292,4 @@ namespace ams::kern {
|
||||
Kernel::GetMemoryManager().Close(KPageTable::GetHeapPhysicalAddress(address), size / PageSize);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1183,7 +1183,7 @@ namespace ams::kern {
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
/* Determine if this is the first termination request. */
|
||||
const bool first_request = [&]() ALWAYS_INLINE_LAMBDA -> bool {
|
||||
const bool first_request = [&] ALWAYS_INLINE_LAMBDA () -> bool {
|
||||
/* Perform an atomic compare-and-swap from false to true. */
|
||||
bool expected = false;
|
||||
return m_termination_requested.CompareExchangeStrong(expected, true);
|
||||
@@ -1315,6 +1315,10 @@ namespace ams::kern {
|
||||
}
|
||||
}
|
||||
|
||||
KThreadContext *KThread::GetContextForSchedulerLoop() {
|
||||
return std::addressof(this->GetContext());
|
||||
}
|
||||
|
||||
KThread *KThread::GetThreadFromId(u64 thread_id) {
|
||||
/* Lock the list. */
|
||||
KThread::ListAccessor accessor;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace ams::kern::svc {
|
||||
/* Check whether the address is aligned. */
|
||||
const bool aligned = util::IsAligned(phys_addr, PageSize);
|
||||
|
||||
auto QueryIoMappingFromPageTable = [&](uint64_t phys_addr, size_t size) ALWAYS_INLINE_LAMBDA -> Result {
|
||||
auto QueryIoMappingFromPageTable = [&] ALWAYS_INLINE_LAMBDA (uint64_t phys_addr, size_t size) -> Result {
|
||||
/* The size must be non-zero. */
|
||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||
|
||||
|
||||
@@ -277,9 +277,6 @@ namespace ams::kern::svc {
|
||||
}
|
||||
|
||||
Result WriteDebugProcessMemory(ams::svc::Handle debug_handle, uintptr_t buffer, uintptr_t address, size_t size) {
|
||||
/* Only allow invoking the svc on development hardware. */
|
||||
R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented());
|
||||
|
||||
/* Validate address / size. */
|
||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
@@ -38,80 +38,6 @@ namespace ams::kern::svc {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetInfoImpl(u64 *out, ams::svc::InfoType info_type, KProcess *process) {
|
||||
switch (info_type) {
|
||||
case ams::svc::InfoType_CoreMask:
|
||||
*out = process->GetCoreMask();
|
||||
break;
|
||||
case ams::svc::InfoType_PriorityMask:
|
||||
*out = process->GetPriorityMask();
|
||||
break;
|
||||
case ams::svc::InfoType_AliasRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetAliasRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_AliasRegionSize:
|
||||
*out = process->GetPageTable().GetAliasRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_HeapRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetHeapRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_HeapRegionSize:
|
||||
*out = process->GetPageTable().GetHeapRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_TotalMemorySize:
|
||||
*out = process->GetTotalUserPhysicalMemorySize();
|
||||
break;
|
||||
case ams::svc::InfoType_UsedMemorySize:
|
||||
*out = process->GetUsedUserPhysicalMemorySize();
|
||||
break;
|
||||
case ams::svc::InfoType_AslrRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetAliasCodeRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_AslrRegionSize:
|
||||
*out = process->GetPageTable().GetAliasCodeRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_StackRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetStackRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_StackRegionSize:
|
||||
*out = process->GetPageTable().GetStackRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_SystemResourceSizeTotal:
|
||||
*out = process->GetTotalSystemResourceSize();
|
||||
break;
|
||||
case ams::svc::InfoType_SystemResourceSizeUsed:
|
||||
*out = process->GetUsedSystemResourceSize();
|
||||
break;
|
||||
case ams::svc::InfoType_ProgramId:
|
||||
*out = process->GetProgramId();
|
||||
break;
|
||||
case ams::svc::InfoType_UserExceptionContextAddress:
|
||||
*out = GetInteger(process->GetProcessLocalRegionAddress());
|
||||
break;
|
||||
case ams::svc::InfoType_TotalNonSystemMemorySize:
|
||||
*out = process->GetTotalNonSystemUserPhysicalMemorySize();
|
||||
break;
|
||||
case ams::svc::InfoType_UsedNonSystemMemorySize:
|
||||
*out = process->GetUsedNonSystemUserPhysicalMemorySize();
|
||||
break;
|
||||
case ams::svc::InfoType_IsApplication:
|
||||
*out = process->IsApplication();
|
||||
break;
|
||||
case ams::svc::InfoType_FreeThreadCount:
|
||||
if (KResourceLimit *resource_limit = process->GetResourceLimit(); resource_limit != nullptr) {
|
||||
const auto current_value = resource_limit->GetCurrentValue(ams::svc::LimitableResource_ThreadCountMax);
|
||||
const auto limit_value = resource_limit->GetLimitValue(ams::svc::LimitableResource_ThreadCountMax);
|
||||
*out = limit_value - current_value;
|
||||
} else {
|
||||
*out = 0;
|
||||
}
|
||||
break;
|
||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
|
||||
switch (info_type) {
|
||||
case ams::svc::InfoType_CoreMask:
|
||||
@@ -140,34 +66,77 @@ namespace ams::kern::svc {
|
||||
|
||||
/* Get the process from its handle. */
|
||||
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(handle);
|
||||
|
||||
#if defined(MESOSPHERE_ENABLE_GET_INFO_OF_DEBUG_PROCESS)
|
||||
/* If we the process is valid, use it. */
|
||||
if (process.IsNotNull()) {
|
||||
return GetInfoImpl(out, info_type, process.GetPointerUnsafe());
|
||||
}
|
||||
|
||||
/* Otherwise, as a mesosphere extension check if we were passed a usable KDebug. */
|
||||
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(handle);
|
||||
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
||||
/* Get the process from the debug object. */
|
||||
/* TODO: ResultInvalidHandle()? */
|
||||
R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated());
|
||||
R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated());
|
||||
|
||||
/* Close the process when we're done. */
|
||||
ON_SCOPE_EXIT { debug->CloseProcess(); };
|
||||
|
||||
/* Return the info. */
|
||||
return GetInfoImpl(out, info_type, debug->GetProcessUnsafe());
|
||||
#else
|
||||
/* Verify that the process is valid. */
|
||||
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
||||
/* Return the relevant info. */
|
||||
return GetInfoImpl(out, info_type, process.GetPointerUnsafe());
|
||||
#endif
|
||||
switch (info_type) {
|
||||
case ams::svc::InfoType_CoreMask:
|
||||
*out = process->GetCoreMask();
|
||||
break;
|
||||
case ams::svc::InfoType_PriorityMask:
|
||||
*out = process->GetPriorityMask();
|
||||
break;
|
||||
case ams::svc::InfoType_AliasRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetAliasRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_AliasRegionSize:
|
||||
*out = process->GetPageTable().GetAliasRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_HeapRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetHeapRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_HeapRegionSize:
|
||||
*out = process->GetPageTable().GetHeapRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_TotalMemorySize:
|
||||
*out = process->GetTotalUserPhysicalMemorySize();
|
||||
break;
|
||||
case ams::svc::InfoType_UsedMemorySize:
|
||||
*out = process->GetUsedUserPhysicalMemorySize();
|
||||
break;
|
||||
case ams::svc::InfoType_AslrRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetAliasCodeRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_AslrRegionSize:
|
||||
*out = process->GetPageTable().GetAliasCodeRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_StackRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetStackRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_StackRegionSize:
|
||||
*out = process->GetPageTable().GetStackRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_SystemResourceSizeTotal:
|
||||
*out = process->GetTotalSystemResourceSize();
|
||||
break;
|
||||
case ams::svc::InfoType_SystemResourceSizeUsed:
|
||||
*out = process->GetUsedSystemResourceSize();
|
||||
break;
|
||||
case ams::svc::InfoType_ProgramId:
|
||||
*out = process->GetProgramId();
|
||||
break;
|
||||
case ams::svc::InfoType_UserExceptionContextAddress:
|
||||
*out = GetInteger(process->GetProcessLocalRegionAddress());
|
||||
break;
|
||||
case ams::svc::InfoType_TotalNonSystemMemorySize:
|
||||
*out = process->GetTotalNonSystemUserPhysicalMemorySize();
|
||||
break;
|
||||
case ams::svc::InfoType_UsedNonSystemMemorySize:
|
||||
*out = process->GetUsedNonSystemUserPhysicalMemorySize();
|
||||
break;
|
||||
case ams::svc::InfoType_IsApplication:
|
||||
*out = process->IsApplication();
|
||||
break;
|
||||
case ams::svc::InfoType_FreeThreadCount:
|
||||
if (KResourceLimit *resource_limit = process->GetResourceLimit(); resource_limit != nullptr) {
|
||||
const auto current_value = resource_limit->GetCurrentValue(ams::svc::LimitableResource_ThreadCountMax);
|
||||
const auto limit_value = resource_limit->GetLimitValue(ams::svc::LimitableResource_ThreadCountMax);
|
||||
*out = limit_value - current_value;
|
||||
} else {
|
||||
*out = 0;
|
||||
}
|
||||
break;
|
||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ams::svc::InfoType_DebuggerAttached:
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("-O3")
|
||||
|
||||
namespace ams::kern::svc {
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("-O3")
|
||||
|
||||
/* ============================= Common ============================= */
|
||||
|
||||
namespace {
|
||||
@@ -315,6 +315,6 @@ namespace ams::kern::svc {
|
||||
return ReplyAndReceiveWithUserBuffer(out_index, message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns);
|
||||
}
|
||||
|
||||
}
|
||||
#pragma GCC pop_options
|
||||
|
||||
#pragma GCC pop_options
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ namespace ams::kern::svc {
|
||||
KResourceLimit *process_resource_limit = resource_limit.IsNotNull() ? resource_limit.GetPointerUnsafe() : std::addressof(Kernel::GetSystemResourceLimit());
|
||||
|
||||
/* Get the pool for the process. */
|
||||
const auto pool = [](u32 flags) ALWAYS_INLINE_LAMBDA -> KMemoryManager::Pool {
|
||||
const auto pool = [] ALWAYS_INLINE_LAMBDA (u32 flags) -> KMemoryManager::Pool {
|
||||
if (GetTargetFirmware() >= TargetFirmware_5_0_0) {
|
||||
switch (flags & ams::svc::CreateProcessFlag_PoolPartitionMask) {
|
||||
case ams::svc::CreateProcessFlag_PoolPartitionApplication:
|
||||
|
||||
@@ -63,7 +63,6 @@ namespace ams::impl {
|
||||
AMS_DEFINE_SYSTEM_THREAD(-7, mitm, InitializeThread);
|
||||
AMS_DEFINE_SYSTEM_THREAD(-1, mitm_sf, QueryServerProcessThread);
|
||||
AMS_DEFINE_SYSTEM_THREAD(16, mitm_fs, RomFileSystemInitializeThread);
|
||||
AMS_DEFINE_SYSTEM_THREAD(16, mitm_fs, RomFileSystemFinalizeThread);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, mitm, DebugThrowThread);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, mitm_sysupdater, IpcServer);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, mitm_sysupdater, AsyncPrepareSdCardUpdateTask);
|
||||
|
||||
@@ -118,12 +118,12 @@ namespace ams::fssystem {
|
||||
|
||||
/* Copy API. */
|
||||
Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size);
|
||||
ALWAYS_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
|
||||
NX_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
|
||||
return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, work_buf_size);
|
||||
}
|
||||
|
||||
Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size);
|
||||
ALWAYS_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
|
||||
NX_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
|
||||
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size);
|
||||
}
|
||||
|
||||
@@ -148,11 +148,11 @@ namespace ams::fssystem {
|
||||
Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
|
||||
Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
|
||||
|
||||
template<s64 RetryMilliSeconds = 100>
|
||||
ALWAYS_INLINE Result RetryFinitelyForTargetLocked(auto f) {
|
||||
template<typename F>
|
||||
NX_INLINE Result RetryFinitelyForTargetLocked(F f) {
|
||||
/* Retry up to 10 times, 100ms between retries. */
|
||||
constexpr s32 MaxRetryCount = 10;
|
||||
constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(RetryMilliSeconds);
|
||||
constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(100);
|
||||
|
||||
s32 remaining_retries = MaxRetryCount;
|
||||
while (true) {
|
||||
|
||||
@@ -66,9 +66,6 @@ namespace ams::hos {
|
||||
Version_12_0_3 = ::ams::TargetFirmware_12_0_3,
|
||||
Version_12_1_0 = ::ams::TargetFirmware_12_1_0,
|
||||
Version_13_0_0 = ::ams::TargetFirmware_13_0_0,
|
||||
Version_13_1_0 = ::ams::TargetFirmware_13_1_0,
|
||||
Version_13_2_0 = ::ams::TargetFirmware_13_2_0,
|
||||
Version_13_2_1 = ::ams::TargetFirmware_13_2_1,
|
||||
|
||||
Version_Current = ::ams::TargetFirmware_Current,
|
||||
|
||||
|
||||
@@ -62,16 +62,20 @@ namespace ams::settings {
|
||||
|
||||
char name[MaxLength];
|
||||
|
||||
static constexpr LanguageCode Encode(util::string_view name) {
|
||||
static constexpr LanguageCode Encode(const char *name, size_t name_size) {
|
||||
LanguageCode out{};
|
||||
for (size_t i = 0; i < MaxLength && i < name.size(); i++) {
|
||||
for (size_t i = 0; i < MaxLength && i < name_size; i++) {
|
||||
out.name[i] = name[i];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static constexpr LanguageCode Encode(const char *name) {
|
||||
return Encode(name, std::strlen(name));
|
||||
}
|
||||
|
||||
template<Language Lang>
|
||||
static constexpr inline LanguageCode EncodeLanguage() {
|
||||
static constexpr inline LanguageCode EncodeLanguage = [] {
|
||||
if constexpr (false) { /* ... */ }
|
||||
#define AMS_MATCH_LANGUAGE(lang, enc) else if constexpr (Lang == Language_##lang) { return LanguageCode::Encode(enc); }
|
||||
AMS_MATCH_LANGUAGE(Japanese, "ja")
|
||||
@@ -94,28 +98,28 @@ namespace ams::settings {
|
||||
AMS_MATCH_LANGUAGE(TraditionalChinese, "zh-Hant")
|
||||
#undef AMS_MATCH_LANGUAGE
|
||||
else { static_assert(Lang != Language_Japanese); }
|
||||
}
|
||||
}();
|
||||
|
||||
static constexpr inline LanguageCode Encode(const Language language) {
|
||||
constexpr LanguageCode EncodedLanguages[Language_Count] = {
|
||||
EncodeLanguage<Language_Japanese>(),
|
||||
EncodeLanguage<Language_AmericanEnglish>(),
|
||||
EncodeLanguage<Language_French>(),
|
||||
EncodeLanguage<Language_German>(),
|
||||
EncodeLanguage<Language_Italian>(),
|
||||
EncodeLanguage<Language_Spanish>(),
|
||||
EncodeLanguage<Language_Chinese>(),
|
||||
EncodeLanguage<Language_Korean>(),
|
||||
EncodeLanguage<Language_Dutch>(),
|
||||
EncodeLanguage<Language_Portuguese>(),
|
||||
EncodeLanguage<Language_Russian>(),
|
||||
EncodeLanguage<Language_Taiwanese>(),
|
||||
EncodeLanguage<Language_BritishEnglish>(),
|
||||
EncodeLanguage<Language_CanadianFrench>(),
|
||||
EncodeLanguage<Language_LatinAmericanSpanish>(),
|
||||
EncodeLanguage<Language_Japanese>,
|
||||
EncodeLanguage<Language_AmericanEnglish>,
|
||||
EncodeLanguage<Language_French>,
|
||||
EncodeLanguage<Language_German>,
|
||||
EncodeLanguage<Language_Italian>,
|
||||
EncodeLanguage<Language_Spanish>,
|
||||
EncodeLanguage<Language_Chinese>,
|
||||
EncodeLanguage<Language_Korean>,
|
||||
EncodeLanguage<Language_Dutch>,
|
||||
EncodeLanguage<Language_Portuguese>,
|
||||
EncodeLanguage<Language_Russian>,
|
||||
EncodeLanguage<Language_Taiwanese>,
|
||||
EncodeLanguage<Language_BritishEnglish>,
|
||||
EncodeLanguage<Language_CanadianFrench>,
|
||||
EncodeLanguage<Language_LatinAmericanSpanish>,
|
||||
/* 4.0.0+ */
|
||||
EncodeLanguage<Language_SimplifiedChinese>(),
|
||||
EncodeLanguage<Language_TraditionalChinese>(),
|
||||
EncodeLanguage<Language_SimplifiedChinese>,
|
||||
EncodeLanguage<Language_TraditionalChinese>,
|
||||
};
|
||||
return EncodedLanguages[language];
|
||||
}
|
||||
|
||||
@@ -54,11 +54,11 @@ namespace ams::sf::cmif {
|
||||
|
||||
void DisposeImpl();
|
||||
|
||||
virtual void AddReference() override {
|
||||
virtual void AddReference() {
|
||||
ServiceObjectImplBase2::AddReferenceImpl();
|
||||
}
|
||||
|
||||
virtual void Release() override {
|
||||
virtual void Release() {
|
||||
if (ServiceObjectImplBase2::ReleaseImpl()) {
|
||||
this->DisposeImpl();
|
||||
}
|
||||
|
||||
@@ -53,32 +53,16 @@ namespace ams::sf::cmif {
|
||||
u32 cmd_id;
|
||||
Result (*handler)(CmifOutHeader **out_header_ptr, ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data);
|
||||
|
||||
constexpr inline bool MatchesVersion(hos::Version hosver) const {
|
||||
constexpr inline bool Matches(u32 cmd_id, hos::Version hosver) const {
|
||||
const bool min_valid = this->hosver_low == hos::Version_Min;
|
||||
const bool max_valid = this->hosver_high == hos::Version_Max;
|
||||
|
||||
return (min_valid || this->hosver_low <= hosver) && (max_valid || hosver <= this->hosver_high);
|
||||
}
|
||||
|
||||
constexpr inline bool Matches(u32 cmd_id, hos::Version hosver) const {
|
||||
return this->cmd_id == cmd_id && this->MatchesVersion(hosver);
|
||||
return this->cmd_id == cmd_id && (min_valid || this->hosver_low <= hosver) && (max_valid || hosver <= this->hosver_high);
|
||||
}
|
||||
|
||||
constexpr inline decltype(handler) GetHandler() const {
|
||||
return this->handler;
|
||||
}
|
||||
|
||||
constexpr inline bool operator>(const ServiceCommandMeta &rhs) const {
|
||||
if (this->cmd_id > rhs.cmd_id) {
|
||||
return true;
|
||||
} else if (this->cmd_id == rhs.cmd_id && this->hosver_low > rhs.hosver_low) {
|
||||
return true;
|
||||
} else if (this->cmd_id == rhs.cmd_id && this->hosver_low == rhs.hosver_low && this->hosver_high == rhs.hosver_high){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<ServiceCommandMeta>::value && sizeof(ServiceCommandMeta) == 0x18, "sizeof(ServiceCommandMeta)");
|
||||
|
||||
|
||||
@@ -85,41 +85,16 @@ namespace ams::sf::impl {
|
||||
constexpr const auto &BaseEntries = ::ams::sf::cmif::ServiceDispatchTraits<BASECLASS>::DispatchTable.GetEntries(); \
|
||||
constexpr size_t BaseSize = BaseEntries.size(); \
|
||||
\
|
||||
constexpr size_t CombinedSize = BaseSize + CurSize; \
|
||||
\
|
||||
std::array<size_t, CombinedSize> map{}; \
|
||||
for (size_t i = 0; i < CombinedSize; ++i) { map[i] = i; } \
|
||||
\
|
||||
for (size_t i = 1; i < CombinedSize; ++i) { \
|
||||
size_t j = i; \
|
||||
while (j > 0) { \
|
||||
const auto li = map[j]; \
|
||||
const auto ri = map[j - 1]; \
|
||||
\
|
||||
const auto &lhs = (li < BaseSize) ? BaseEntries[li] : cur_entries[li - BaseSize]; \
|
||||
const auto &rhs = (ri < BaseSize) ? BaseEntries[ri] : cur_entries[ri - BaseSize]; \
|
||||
\
|
||||
if (!(rhs > lhs)) { \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
std::swap(map[j], map[j - 1]); \
|
||||
\
|
||||
--j; \
|
||||
} \
|
||||
std::array<::ams::sf::cmif::ServiceCommandMeta, BaseSize + CurSize> combined_entries{}; \
|
||||
for (size_t i = 0; i < BaseSize; ++i) { \
|
||||
combined_entries[i] = BaseEntries[i]; \
|
||||
} \
|
||||
\
|
||||
std::array<::ams::sf::cmif::ServiceCommandMeta, CombinedSize> combined_entries{}; \
|
||||
for (size_t i = 0; i < CombinedSize; ++i) { \
|
||||
if (map[i] < BaseSize) { \
|
||||
combined_entries[i] = BaseEntries[map[i]]; \
|
||||
} else { \
|
||||
combined_entries[i] = cur_entries[map[i] - BaseSize]; \
|
||||
} \
|
||||
for (size_t i = 0; i < CurSize; ++i) { \
|
||||
combined_entries[BaseSize + i] = cur_entries[i]; \
|
||||
} \
|
||||
\
|
||||
return ::ams::sf::cmif::ServiceDispatchTable { combined_entries }; \
|
||||
}() \
|
||||
} () \
|
||||
}; \
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace ams::sf {
|
||||
return lmem::FreeToExpHeap(m_handle, buffer);
|
||||
}
|
||||
|
||||
virtual bool IsEqualImpl(const MemoryResource &resource) const override {
|
||||
virtual bool IsEqualImpl(const MemoryResource &resource) const {
|
||||
return this == std::addressof(resource);
|
||||
}
|
||||
};
|
||||
@@ -76,9 +76,9 @@ namespace ams::sf {
|
||||
return lmem::FreeToUnitHeap(m_handle, buffer);
|
||||
}
|
||||
|
||||
virtual bool IsEqualImpl(const MemoryResource &resource) const override {
|
||||
virtual bool IsEqualImpl(const MemoryResource &resource) const {
|
||||
return this == std::addressof(resource);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -37,9 +37,9 @@ namespace ams::sf {
|
||||
return m_standard_allocator->Free(buffer);
|
||||
}
|
||||
|
||||
virtual bool IsEqualImpl(const MemoryResource &resource) const override {
|
||||
virtual bool IsEqualImpl(const MemoryResource &resource) const {
|
||||
return this == std::addressof(resource);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace ams::sf {
|
||||
public:
|
||||
class Object;
|
||||
using Allocator = StatelessDummyAllocator;
|
||||
using StatelessAllocator = typename Policy::template StatelessAllocator<Object>;
|
||||
using StatelessAllocator = typename Policy::StatelessAllocator<Object>;
|
||||
|
||||
class Object final : private ::ams::sf::impl::ServiceObjectImplBase2, public Base {
|
||||
NON_COPYABLE(Object);
|
||||
|
||||
@@ -40,8 +40,8 @@ namespace ams::sm {
|
||||
return out;
|
||||
}
|
||||
|
||||
static constexpr ServiceName Encode(util::string_view name) {
|
||||
return Encode(name.data(), name.size());
|
||||
static constexpr ServiceName Encode(const char *name) {
|
||||
return Encode(name, std::strlen(name));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ namespace ams::socket {
|
||||
|
||||
s32 Shutdown(s32 desc, ShutdownMethod how);
|
||||
|
||||
s32 Socket(Family domain, Type type, Protocol protocol);
|
||||
s32 SocketExempt(Family domain, Type type, Protocol protocol);
|
||||
|
||||
s32 Accept(s32 desc, SockAddr *out_address, SockLenT *out_addr_len);
|
||||
|
||||
@@ -57,42 +57,4 @@ namespace ams::socket {
|
||||
}
|
||||
};
|
||||
|
||||
class SystemConfigLightDefault : public Config {
|
||||
public:
|
||||
static constexpr size_t DefaultTcpInitialSendBufferSize = 16_KB;
|
||||
static constexpr size_t DefaultTcpInitialReceiveBufferSize = 16_KB;
|
||||
static constexpr size_t DefaultTcpAutoSendBufferSizeMax = 0_KB;
|
||||
static constexpr size_t DefaultTcpAutoReceiveBufferSizeMax = 0_KB;
|
||||
static constexpr size_t DefaultUdpSendBufferSize = 9_KB;
|
||||
static constexpr size_t DefaultUdpReceiveBufferSize = 42240;
|
||||
static constexpr auto DefaultSocketBufferEfficiency = 2;
|
||||
static constexpr auto DefaultConcurrency = 2;
|
||||
static constexpr size_t DefaultAllocatorPoolSize = 64_KB;
|
||||
|
||||
static constexpr size_t PerTcpSocketWorstCaseMemoryPoolSize = [] {
|
||||
constexpr size_t WorstCaseTcpSendBufferSize = AlignMss(std::max(DefaultTcpInitialSendBufferSize, DefaultTcpAutoSendBufferSizeMax));
|
||||
constexpr size_t WorstCaseTcpReceiveBufferSize = AlignMss(std::max(DefaultTcpInitialReceiveBufferSize, DefaultTcpAutoReceiveBufferSizeMax));
|
||||
|
||||
return util::AlignUp(WorstCaseTcpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseTcpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize);
|
||||
}();
|
||||
|
||||
static constexpr size_t PerUdpSocketWorstCaseMemoryPoolSize = [] {
|
||||
constexpr size_t WorstCaseUdpSendBufferSize = AlignMss(DefaultUdpSendBufferSize);
|
||||
constexpr size_t WorstCaseUdpReceiveBufferSize = AlignMss(DefaultUdpReceiveBufferSize);
|
||||
|
||||
return util::AlignUp(WorstCaseUdpSendBufferSize * DefaultSocketBufferEfficiency + WorstCaseUdpReceiveBufferSize * DefaultSocketBufferEfficiency, os::MemoryPageSize);
|
||||
}();
|
||||
public:
|
||||
constexpr SystemConfigLightDefault(void *mp, size_t mp_sz, size_t ap, int c=DefaultConcurrency)
|
||||
: Config(mp, mp_sz, ap,
|
||||
DefaultTcpInitialSendBufferSize, DefaultTcpInitialReceiveBufferSize,
|
||||
DefaultTcpAutoSendBufferSizeMax, DefaultTcpAutoReceiveBufferSizeMax,
|
||||
DefaultUdpSendBufferSize, DefaultUdpReceiveBufferSize,
|
||||
DefaultSocketBufferEfficiency, c)
|
||||
{
|
||||
/* Mark as system. */
|
||||
m_system = true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace ams::spl::impl {
|
||||
|
||||
Result AllocateAesKeySlot(s32 *out_keyslot);
|
||||
Result DeallocateAesKeySlot(s32 keyslot);
|
||||
Result TestAesKeySlot(s32 *out_index, bool *out_virtual, s32 keyslot);
|
||||
Result TestAesKeySlot(s32 *out_index, s32 keyslot);
|
||||
|
||||
os::SystemEvent *GetAesKeySlotAvailableEvent();
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace ams::time {
|
||||
AMS_ASSERT(rhs.IsValid());
|
||||
}
|
||||
|
||||
constexpr auto ToUint64 = [](const time::CalendarTime &time) ALWAYS_INLINE_LAMBDA {
|
||||
constexpr auto ToUint64 = [] ALWAYS_INLINE_LAMBDA (const time::CalendarTime &time) {
|
||||
return (static_cast<u64>(time.year) << 40) |
|
||||
(static_cast<u64>(time.month) << 32) |
|
||||
(static_cast<u64>(time.day) << 24) |
|
||||
|
||||
@@ -40,28 +40,12 @@ namespace ams::tipc::impl {
|
||||
#define AMS_TIPC_IMPL_EXTRACT_SYNC_METHOD_ARGUMENTS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
|
||||
using NAME##ArgumentsType = ::ams::tipc::impl::SyncFunctionArgsType<&NAME##ArgumentsFunctionHolder::f>;
|
||||
|
||||
#define AMS_TIPC_IMPL_GET_MAXIMUM_REQUEST_SIZE(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
|
||||
, ::ams::tipc::impl::CommandMetaInfo<CMD_ID + 0x10, NAME##ArgumentsType>::InMessageTotalSize
|
||||
|
||||
#define AMS_TIPC_IMPL_GET_MAXIMUM_RESPONSE_SIZE(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
|
||||
, ::ams::tipc::impl::CommandMetaInfo<CMD_ID + 0x10, NAME##ArgumentsType>::OutMessageTotalSize
|
||||
|
||||
#define AMS_TIPC_IMPL_DEFINE_INTERFACE(BASECLASS, CLASSNAME, CMD_MACRO) \
|
||||
class CLASSNAME : public BASECLASS { \
|
||||
private: \
|
||||
CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_DEFINE_SYNC_METHOD_HOLDER) \
|
||||
public: \
|
||||
CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_EXTRACT_SYNC_METHOD_ARGUMENTS) \
|
||||
public: \
|
||||
static constexpr size_t MaximumRequestSize = std::max<size_t>({ \
|
||||
0 \
|
||||
CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_GET_MAXIMUM_REQUEST_SIZE) \
|
||||
}); \
|
||||
\
|
||||
static constexpr size_t MaximumResponseSize = std::max<size_t>({ \
|
||||
0 \
|
||||
CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_GET_MAXIMUM_RESPONSE_SIZE) \
|
||||
}); \
|
||||
};
|
||||
|
||||
#define AMS_TIPC_IMPL_DEFINE_CONCEPT_HELPERS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
|
||||
|
||||
@@ -319,9 +319,6 @@ namespace ams::tipc::impl {
|
||||
static constexpr auto OutMessageResultIndex = svc::ipc::MessageBuffer::GetRawDataIndex(OutMessageHeader, OutSpecialHeader);
|
||||
static constexpr auto OutMessageRawDataIndex = OutMessageResultIndex + 1;
|
||||
|
||||
static constexpr size_t InMessageTotalSize = (InMessageRawDataIndex * sizeof(u32)) + InDataSize;
|
||||
static constexpr size_t OutMessageTotalSize = (OutMessageRawDataIndex * sizeof(u32)) + OutDataSize;
|
||||
|
||||
/* Construction of argument serialization structs. */
|
||||
private:
|
||||
template<typename>
|
||||
@@ -475,7 +472,7 @@ namespace ams::tipc::impl {
|
||||
using OutRawHolderType = OutRawHolder<CommandMeta::OutDataSize, CommandMeta::OutDataAlign, CommandMeta::OutMessageRawDataIndex>;
|
||||
using OutHandleHolderType = OutHandleHolder<CommandMeta::NumOutMoveHandles, CommandMeta::NumOutCopyHandles, CommandMeta::OutMessageHandleIndex>;
|
||||
private:
|
||||
static constexpr u64 GetMessageHeaderForCheck(const svc::ipc::MessageBuffer::MessageHeader &header) {
|
||||
static consteval u64 GetMessageHeaderForCheck(const svc::ipc::MessageBuffer::MessageHeader &header) {
|
||||
using Value = util::BitPack32::Field<0, BITSIZEOF(util::BitPack32)>;
|
||||
|
||||
const util::BitPack32 *data = header.GetData();
|
||||
@@ -485,7 +482,7 @@ namespace ams::tipc::impl {
|
||||
return static_cast<u64>(lower) | (static_cast<u64>(upper) << BITSIZEOF(u32));
|
||||
}
|
||||
|
||||
static constexpr u32 GetSpecialHeaderForCheck(const svc::ipc::MessageBuffer::SpecialHeader &header) {
|
||||
static consteval u32 GetSpecialHeaderForCheck(const svc::ipc::MessageBuffer::SpecialHeader &header) {
|
||||
using Value = util::BitPack32::Field<0, BITSIZEOF(util::BitPack32)>;
|
||||
|
||||
return header.GetHeader()->Get<Value>();
|
||||
|
||||
@@ -44,17 +44,16 @@ namespace ams::tipc {
|
||||
|
||||
}
|
||||
|
||||
class DeferrableBaseImpl : public impl::DeferrableBaseTag {
|
||||
class DeferrableBase : public impl::DeferrableBaseTag {
|
||||
private:
|
||||
DeferralManagerBase *m_deferral_manager;
|
||||
ObjectHolder m_object_holder;
|
||||
uintptr_t m_resume_key;
|
||||
const u32 m_message_buffer_size;
|
||||
u8 m_message_buffer_base[0];
|
||||
u8 m_message_buffer[svc::ipc::MessageBufferSize];
|
||||
public:
|
||||
ALWAYS_INLINE DeferrableBaseImpl(u32 mb_size) : m_deferral_manager(nullptr), m_object_holder(), m_resume_key(), m_message_buffer_size(mb_size) { /* ... */ }
|
||||
ALWAYS_INLINE DeferrableBase() : m_deferral_manager(nullptr), m_object_holder(), m_resume_key() { /* ... */ }
|
||||
|
||||
~DeferrableBaseImpl();
|
||||
~DeferrableBase();
|
||||
|
||||
ALWAYS_INLINE void SetDeferralManager(DeferralManagerBase *manager, os::NativeHandle reply_target, ServiceObjectBase *object) {
|
||||
m_deferral_manager = manager;
|
||||
@@ -68,7 +67,7 @@ namespace ams::tipc {
|
||||
template<IsResumeKey ResumeKey>
|
||||
ALWAYS_INLINE void RegisterRetry(ResumeKey key) {
|
||||
m_resume_key = ConvertToInternalResumeKey(key);
|
||||
std::memcpy(m_message_buffer_base, svc::ipc::GetMessageBuffer(), m_message_buffer_size);
|
||||
std::memcpy(m_message_buffer, svc::ipc::GetMessageBuffer(), sizeof(m_message_buffer));
|
||||
}
|
||||
|
||||
template<IsResumeKey ResumeKey, typename F>
|
||||
@@ -86,49 +85,11 @@ namespace ams::tipc {
|
||||
m_resume_key = 0;
|
||||
|
||||
/* Restore message buffer. */
|
||||
std::memcpy(svc::ipc::GetMessageBuffer(), m_message_buffer_base, m_message_buffer_size);
|
||||
std::memcpy(svc::ipc::GetMessageBuffer(), m_message_buffer, sizeof(m_message_buffer));
|
||||
|
||||
/* Process the request. */
|
||||
return port_manager->ProcessDeferredRequest(m_object_holder);
|
||||
}
|
||||
protected:
|
||||
static consteval size_t GetMessageBufferOffsetBase();
|
||||
};
|
||||
static_assert(std::is_standard_layout<DeferrableBaseImpl>::value);
|
||||
|
||||
template<size_t _MessageBufferRequiredSize>
|
||||
class DeferrableBaseImplWithBuffer : public DeferrableBaseImpl {
|
||||
private:
|
||||
static constexpr size_t MessageBufferRequiredSize = _MessageBufferRequiredSize;
|
||||
private:
|
||||
u8 m_message_buffer[MessageBufferRequiredSize];
|
||||
public:
|
||||
DeferrableBaseImplWithBuffer();
|
||||
private:
|
||||
static consteval size_t GetMessageBufferOffset();
|
||||
};
|
||||
|
||||
consteval size_t DeferrableBaseImpl::GetMessageBufferOffsetBase() {
|
||||
return AMS_OFFSETOF(DeferrableBaseImpl, m_message_buffer_base);
|
||||
}
|
||||
|
||||
template<size_t _MessageBufferRequiredSize>
|
||||
consteval size_t DeferrableBaseImplWithBuffer<_MessageBufferRequiredSize>::GetMessageBufferOffset() {
|
||||
return AMS_OFFSETOF(DeferrableBaseImplWithBuffer<_MessageBufferRequiredSize>, m_message_buffer);
|
||||
}
|
||||
|
||||
template<size_t _MessageBufferRequiredSize>
|
||||
ALWAYS_INLINE DeferrableBaseImplWithBuffer<_MessageBufferRequiredSize>::DeferrableBaseImplWithBuffer() : DeferrableBaseImpl(MessageBufferRequiredSize) {
|
||||
static_assert(GetMessageBufferOffsetBase() == GetMessageBufferOffset());
|
||||
static_assert(sizeof(DeferrableBaseImplWithBuffer<_MessageBufferRequiredSize>) >= sizeof(DeferrableBaseImpl) + MessageBufferRequiredSize);
|
||||
}
|
||||
|
||||
template<typename Interface, size_t MaximumDefaultRequestSize = 0>
|
||||
class DeferrableBase : public DeferrableBaseImplWithBuffer<std::max(Interface::MaximumRequestSize, MaximumDefaultRequestSize)> {
|
||||
private:
|
||||
using BaseImpl = DeferrableBaseImplWithBuffer<std::max(Interface::MaximumRequestSize, MaximumDefaultRequestSize)>;
|
||||
public:
|
||||
using BaseImpl::BaseImpl;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
@@ -139,11 +100,11 @@ namespace ams::tipc {
|
||||
NON_MOVEABLE(DeferralManagerBase);
|
||||
private:
|
||||
size_t m_object_count;
|
||||
DeferrableBaseImpl *m_objects_base[0];
|
||||
DeferrableBase *m_objects_base[0];
|
||||
public:
|
||||
ALWAYS_INLINE DeferralManagerBase() : m_object_count(0) { /* ... */ }
|
||||
|
||||
void AddObject(DeferrableBaseImpl &object, os::NativeHandle reply_target, ServiceObjectBase *service_object) {
|
||||
void AddObject(DeferrableBase &object, os::NativeHandle reply_target, ServiceObjectBase *service_object) {
|
||||
/* Set ourselves as the manager for the object. */
|
||||
object.SetDeferralManager(this, reply_target, service_object);
|
||||
|
||||
@@ -152,7 +113,7 @@ namespace ams::tipc {
|
||||
m_objects_base[m_object_count++] = std::addressof(object);
|
||||
}
|
||||
|
||||
void RemoveObject(DeferrableBaseImpl *object) {
|
||||
void RemoveObject(DeferrableBase *object) {
|
||||
/* If the object is present, remove it. */
|
||||
for (size_t i = 0; i < m_object_count; ++i) {
|
||||
if (m_objects_base[i] == object) {
|
||||
@@ -187,7 +148,7 @@ namespace ams::tipc {
|
||||
};
|
||||
static_assert(std::is_standard_layout<DeferralManagerBase>::value);
|
||||
|
||||
inline DeferrableBaseImpl::~DeferrableBaseImpl() {
|
||||
inline DeferrableBase::~DeferrableBase() {
|
||||
AMS_ASSUME(m_deferral_manager != nullptr);
|
||||
m_deferral_manager->RemoveObject(this);
|
||||
}
|
||||
@@ -195,7 +156,7 @@ namespace ams::tipc {
|
||||
template<size_t N> requires (N > 0)
|
||||
class DeferralManager final : public DeferralManagerBase {
|
||||
private:
|
||||
DeferrableBaseImpl *m_objects[N];
|
||||
DeferrableBase *m_objects[N];
|
||||
public:
|
||||
DeferralManager();
|
||||
private:
|
||||
@@ -206,15 +167,15 @@ namespace ams::tipc {
|
||||
return AMS_OFFSETOF(DeferralManagerBase, m_objects_base);
|
||||
}
|
||||
|
||||
template<size_t N> requires (N > 0)
|
||||
template<size_t N>
|
||||
consteval size_t DeferralManager<N>::GetObjectPointersOffset() {
|
||||
return AMS_OFFSETOF(DeferralManager<N>, m_objects);
|
||||
}
|
||||
|
||||
template<size_t N> requires (N > 0)
|
||||
template<size_t N>
|
||||
inline DeferralManager<N>::DeferralManager() : DeferralManagerBase() {
|
||||
static_assert(GetObjectPointersOffset() == GetObjectPointersOffsetBase());
|
||||
static_assert(sizeof(DeferralManager<N>) == sizeof(DeferralManagerBase) + N * sizeof(DeferrableBaseImpl *));
|
||||
static_assert(sizeof(DeferralManager<N>) == sizeof(DeferralManagerBase) + N * sizeof(DeferrableBase *));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -686,7 +686,7 @@ namespace ams::tipc {
|
||||
}
|
||||
|
||||
/* Try to reply/receive. */
|
||||
const Result result = [&]() ALWAYS_INLINE_LAMBDA -> Result {
|
||||
const Result result = [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
os::MultiWaitHolderType *signaled_holder = nullptr;
|
||||
ON_SCOPE_EXIT { AMS_ABORT_UNLESS(signaled_holder == nullptr); };
|
||||
return m_object_manager->ReplyAndReceive(std::addressof(signaled_holder), out_object, reply_target, std::addressof(m_multi_wait));
|
||||
@@ -747,7 +747,7 @@ namespace ams::tipc {
|
||||
using PortManager = PortManagerImpl;
|
||||
private:
|
||||
PortManager m_port_manager;
|
||||
typename PortInfo::Allocator m_port_allocator;
|
||||
PortInfo::Allocator m_port_allocator;
|
||||
public:
|
||||
constexpr ServerManagerImpl() : m_port_manager(), m_port_allocator() { /* ... */ }
|
||||
|
||||
|
||||
@@ -18,28 +18,41 @@
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/os_sdk_mutex.hpp>
|
||||
|
||||
#define AMS_SINGLETON_TRAITS(_CLASSNAME_) \
|
||||
private: \
|
||||
NON_COPYABLE(_CLASSNAME_); \
|
||||
NON_MOVEABLE(_CLASSNAME_); \
|
||||
private: \
|
||||
_CLASSNAME_ (); \
|
||||
public: \
|
||||
static _CLASSNAME_ &GetInstance() { \
|
||||
AMS_FUNCTION_LOCAL_STATIC(_CLASSNAME_, s_singleton_instance); \
|
||||
\
|
||||
return s_singleton_instance; \
|
||||
#define AMS_SINGLETON_TRAITS(_CLASSNAME_) \
|
||||
private: \
|
||||
NON_COPYABLE(_CLASSNAME_); \
|
||||
NON_MOVEABLE(_CLASSNAME_); \
|
||||
private: \
|
||||
_CLASSNAME_ (); \
|
||||
public: \
|
||||
static _CLASSNAME_ &GetInstance() { \
|
||||
/* Declare singleton instance variables. */ \
|
||||
static constinit ::ams::util::TypedStorage<_CLASSNAME_> s_singleton_storage; \
|
||||
static constinit ::ams::os::SdkMutex s_singleton_mutex; \
|
||||
static constinit bool s_initialized_singleton = false; \
|
||||
\
|
||||
/* Ensure the instance is created. */ \
|
||||
if (AMS_UNLIKELY(!s_initialized_singleton)) { \
|
||||
std::scoped_lock lk(s_singleton_mutex); \
|
||||
\
|
||||
if (AMS_LIKELY(!s_initialized_singleton)) { \
|
||||
new (::ams::util::GetPointer(s_singleton_storage)) _CLASSNAME_; \
|
||||
s_initialized_singleton = true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return ::ams::util::GetReference(s_singleton_storage); \
|
||||
}
|
||||
|
||||
#define AMS_CONSTINIT_SINGLETON_TRAITS(_CLASSNAME_) \
|
||||
private: \
|
||||
NON_COPYABLE(_CLASSNAME_); \
|
||||
NON_MOVEABLE(_CLASSNAME_); \
|
||||
private: \
|
||||
constexpr _CLASSNAME_ () = default; \
|
||||
public: \
|
||||
static _CLASSNAME_ &GetInstance() { \
|
||||
/* Declare singleton instance variables. */ \
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(_CLASSNAME_, s_singleton_instance); \
|
||||
return s_singleton_instance; \
|
||||
#define AMS_CONSTINIT_SINGLETON_TRAITS(_CLASSNAME_) \
|
||||
private: \
|
||||
NON_COPYABLE(_CLASSNAME_); \
|
||||
NON_MOVEABLE(_CLASSNAME_); \
|
||||
private: \
|
||||
constexpr _CLASSNAME_ () = default; \
|
||||
public: \
|
||||
static _CLASSNAME_ &GetInstance() { \
|
||||
/* Declare singleton instance variables. */ \
|
||||
static constinit _CLASSNAME_ s_singleton_instance; \
|
||||
return s_singleton_instance; \
|
||||
}
|
||||
|
||||
@@ -188,12 +188,6 @@ namespace ams::boot2 {
|
||||
return enable_htc != 0;
|
||||
}
|
||||
|
||||
bool IsStandaloneGdbstubEnabled() {
|
||||
u8 enable_gdbstub = 0;
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(enable_gdbstub), sizeof(enable_gdbstub), "atmosphere", "enable_standalone_gdbstub");
|
||||
return enable_gdbstub != 0;
|
||||
}
|
||||
|
||||
bool IsAtmosphereLogManagerEnabled() {
|
||||
/* If htc is enabled, ams log manager is enabled. */
|
||||
if (IsHtcEnabled()) {
|
||||
@@ -409,9 +403,6 @@ namespace ams::boot2 {
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Htc, ncm::StorageId::None), 0);
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Cs, ncm::StorageId::None), 0);
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0);
|
||||
} else if (IsStandaloneGdbstubEnabled()) {
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::DmntGen2, ncm::StorageId::None), 0);
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0);
|
||||
} else {
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Dmnt, ncm::StorageId::None), 0);
|
||||
LaunchProgram(nullptr, ncm::ProgramLocation::Make(ncm::SystemProgramId::Tma, ncm::StorageId::BuiltInSystem), 0);
|
||||
|
||||
@@ -73,7 +73,18 @@ namespace ams::erpt::srv {
|
||||
}
|
||||
|
||||
bool IsProductionMode() {
|
||||
AMS_FUNCTION_LOCAL_STATIC(bool, s_is_prod_mode, IsProductionModeImpl());
|
||||
static constinit bool s_initialized = false;
|
||||
static constinit bool s_is_prod_mode = true;
|
||||
static constinit os::SdkMutex s_mutex;
|
||||
|
||||
if (AMS_UNLIKELY(!s_initialized)) {
|
||||
std::scoped_lock lk(s_mutex);
|
||||
|
||||
if (AMS_LIKELY(!s_initialized)) {
|
||||
s_is_prod_mode = IsProductionModeImpl();
|
||||
s_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
return s_is_prod_mode;
|
||||
}
|
||||
|
||||
@@ -89,8 +89,9 @@ namespace ams::fs {
|
||||
Result DeleteSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id) {
|
||||
const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, id);
|
||||
|
||||
static_assert(sizeof(attribute) == sizeof(::FsSaveDataAttribute));
|
||||
return fsDeleteSaveDataFileSystemBySaveDataAttribute(static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast<const ::FsSaveDataAttribute *>(std::addressof(attribute)));
|
||||
/* TODO: Libnx binding for DeleteSaveDataFileSystemBySaveDataAttribute */
|
||||
AMS_UNUSED(space_id, attribute);
|
||||
AMS_ABORT();
|
||||
}
|
||||
|
||||
Result GetSaveDataFlags(u32 *out, SaveDataId id) {
|
||||
|
||||
@@ -112,13 +112,13 @@ namespace ams::fssystem {
|
||||
NcaCryptoConfiguration g_nca_crypto_configuration_prod;
|
||||
|
||||
constexpr inline s32 KeySlotCacheEntryCount = 3;
|
||||
constinit KeySlotCache g_key_slot_cache;
|
||||
constinit util::optional<KeySlotCacheEntry> g_key_slot_cache_entry[KeySlotCacheEntryCount];
|
||||
KeySlotCache g_key_slot_cache;
|
||||
util::optional<KeySlotCacheEntry> g_key_slot_cache_entry[KeySlotCacheEntryCount];
|
||||
|
||||
spl::AccessKey &GetNcaKekAccessKey(s32 key_type) {
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(spl::AccessKey, s_nca_kek_access_key_array[KeyAreaEncryptionKeyCount]);
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(spl::AccessKey, s_nca_header_kek_access_key);
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(spl::AccessKey, s_invalid_nca_kek_access_key);
|
||||
static spl::AccessKey s_nca_kek_access_key_array[KeyAreaEncryptionKeyCount] = {};
|
||||
static spl::AccessKey s_nca_header_kek_access_key = {};
|
||||
static spl::AccessKey s_invalid_nca_kek_access_key = {};
|
||||
|
||||
if (key_type > static_cast<s32>(KeyType::NcaHeaderKey) || IsInvalidKeyTypeValue(key_type)) {
|
||||
return s_invalid_nca_kek_access_key;
|
||||
|
||||
@@ -26,20 +26,42 @@ namespace ams::gpio::driver::impl {
|
||||
alignas(os::MemoryPageSize) u8 g_interrupt_thread_stack[InterruptThreadStackSize];
|
||||
|
||||
gpio::driver::IGpioDriver::List &GetGpioDriverList() {
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(gpio::driver::IGpioDriver::List, s_gpio_driver_list);
|
||||
static constinit gpio::driver::IGpioDriver::List s_gpio_driver_list;
|
||||
return s_gpio_driver_list;
|
||||
}
|
||||
|
||||
ddsf::EventHandlerManager &GetInterruptHandlerManager() {
|
||||
AMS_FUNCTION_LOCAL_STATIC(ddsf::EventHandlerManager, s_interrupt_handler_manager);
|
||||
static constinit util::TypedStorage<ddsf::EventHandlerManager> s_interrupt_handler_manager;
|
||||
static constinit bool s_initialized = false;
|
||||
static constinit os::SdkMutex s_mutex;
|
||||
|
||||
return s_interrupt_handler_manager;
|
||||
if (AMS_UNLIKELY(!s_initialized)) {
|
||||
std::scoped_lock lk(s_mutex);
|
||||
|
||||
if (AMS_LIKELY(!s_initialized)) {
|
||||
util::ConstructAt(s_interrupt_handler_manager);
|
||||
s_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
return util::GetReference(s_interrupt_handler_manager);
|
||||
}
|
||||
|
||||
ddsf::DeviceCodeEntryManager &GetDeviceCodeEntryManager() {
|
||||
AMS_FUNCTION_LOCAL_STATIC(ddsf::DeviceCodeEntryManager, s_device_code_entry_manager, ddsf::GetDeviceCodeEntryHolderMemoryResource());
|
||||
static constinit util::TypedStorage<ddsf::DeviceCodeEntryManager> s_device_code_entry_manager;
|
||||
static constinit bool s_initialized = false;
|
||||
static constinit os::SdkMutex s_mutex;
|
||||
|
||||
return s_device_code_entry_manager;
|
||||
if (AMS_UNLIKELY(!s_initialized)) {
|
||||
std::scoped_lock lk(s_mutex);
|
||||
|
||||
if (AMS_LIKELY(!s_initialized)) {
|
||||
util::ConstructAt(s_device_code_entry_manager, ddsf::GetDeviceCodeEntryHolderMemoryResource());
|
||||
s_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
return util::GetReference(s_device_code_entry_manager);
|
||||
}
|
||||
|
||||
void InterruptThreadFunction(void *arg) {
|
||||
|
||||
@@ -196,7 +196,7 @@ namespace ams::htclow::ctrl {
|
||||
/* Lock ourselves. */
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
auto IsSupportedServiceChannel = [](const impl::ChannelInternalType &channel, const impl::ChannelInternalType *supported, int num_supported) ALWAYS_INLINE_LAMBDA -> bool {
|
||||
auto IsSupportedServiceChannel = [] ALWAYS_INLINE_LAMBDA (const impl::ChannelInternalType &channel, const impl::ChannelInternalType *supported, int num_supported) -> bool {
|
||||
for (auto i = 0; i < num_supported; ++i) {
|
||||
if (channel.module_id == supported[i].module_id && channel.channel_id == supported[i].channel_id) {
|
||||
return true;
|
||||
|
||||
@@ -95,17 +95,16 @@ namespace ams::i2c::driver::board::nintendo::nx {
|
||||
}
|
||||
}
|
||||
|
||||
constinit util::TypedStorage<impl::I2cBusAccessorManager> g_bus_accessor_manager;
|
||||
constinit util::TypedStorage<impl::I2cDevicePropertyManager> g_device_manager;
|
||||
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
/* Initialize managers. */
|
||||
util::ConstructAt(g_bus_accessor_manager, ddsf::GetMemoryResource());
|
||||
util::ConstructAt(g_device_manager, ddsf::GetMemoryResource());
|
||||
static constinit util::TypedStorage<impl::I2cBusAccessorManager> s_bus_accessor_manager;
|
||||
static constinit util::TypedStorage<impl::I2cDevicePropertyManager> s_device_manager;
|
||||
|
||||
return Initialize(util::GetReference(g_bus_accessor_manager), util::GetReference(g_device_manager));
|
||||
util::ConstructAt(s_bus_accessor_manager, ddsf::GetMemoryResource());
|
||||
util::ConstructAt(s_device_manager, ddsf::GetMemoryResource());
|
||||
|
||||
return Initialize(util::GetReference(s_bus_accessor_manager), util::GetReference(s_device_manager));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,14 +24,25 @@ namespace ams::i2c::driver::impl {
|
||||
constinit int g_init_count = 0;
|
||||
|
||||
i2c::driver::II2cDriver::List &GetI2cDriverList() {
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(i2c::driver::II2cDriver::List, s_driver_list);
|
||||
static constinit i2c::driver::II2cDriver::List s_driver_list;
|
||||
return s_driver_list;
|
||||
}
|
||||
|
||||
ddsf::DeviceCodeEntryManager &GetDeviceCodeEntryManager() {
|
||||
AMS_FUNCTION_LOCAL_STATIC(ddsf::DeviceCodeEntryManager, s_device_code_entry_manager, ddsf::GetDeviceCodeEntryHolderMemoryResource());
|
||||
static constinit util::TypedStorage<ddsf::DeviceCodeEntryManager> s_device_code_entry_manager;
|
||||
static constinit bool s_initialized = false;
|
||||
static constinit os::SdkMutex s_mutex;
|
||||
|
||||
return s_device_code_entry_manager;
|
||||
if (AMS_UNLIKELY(!s_initialized)) {
|
||||
std::scoped_lock lk(s_mutex);
|
||||
|
||||
if (AMS_LIKELY(!s_initialized)) {
|
||||
util::ConstructAt(s_device_code_entry_manager, ddsf::GetDeviceCodeEntryHolderMemoryResource());
|
||||
s_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
return util::GetReference(s_device_code_entry_manager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ extern "C" {
|
||||
constinit u32 __nx_fs_num_sessions = 1;
|
||||
constinit u32 __nx_applet_type = AppletType_None;
|
||||
|
||||
constinit bool __nx_fsdev_support_cwd = false;
|
||||
|
||||
extern int __system_argc;
|
||||
extern char** __system_argv;
|
||||
|
||||
|
||||
@@ -34,8 +34,7 @@ namespace ams::lm::srv {
|
||||
}
|
||||
|
||||
EventLogTransmitter &EventLogTransmitter::GetDefaultInstance() {
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(EventLogTransmitter, s_default_event_log_transmitter, DefaultFlushFunction);
|
||||
|
||||
static constinit EventLogTransmitter s_default_event_log_transmitter(DefaultFlushFunction);
|
||||
return s_default_event_log_transmitter;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,10 +63,8 @@ namespace ams::lm::srv {
|
||||
}
|
||||
|
||||
bool DefaultFlushFunction(const u8 *data, size_t size) {
|
||||
/* Declare persistent clock-updated state storage. */
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_is_user_system_clock_updated, false);
|
||||
|
||||
/* Update clock. */
|
||||
static constinit bool s_is_user_system_clock_updated = false;
|
||||
if (!s_is_user_system_clock_updated) {
|
||||
UpdateUserSystemClock(data, size);
|
||||
s_is_user_system_clock_updated = true;
|
||||
@@ -86,8 +84,8 @@ namespace ams::lm::srv {
|
||||
}
|
||||
|
||||
LogBuffer &LogBuffer::GetDefaultInstance() {
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(u8, s_default_buffers[128_KB * 2]);
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(LogBuffer, s_default_log_buffer, s_default_buffers, sizeof(s_default_buffers), DefaultFlushFunction);
|
||||
static constinit u8 s_default_buffers[128_KB * 2];
|
||||
static constinit LogBuffer s_default_log_buffer(s_default_buffers, sizeof(s_default_buffers), DefaultFlushFunction);
|
||||
|
||||
return s_default_log_buffer;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
namespace ams::lm::srv {
|
||||
|
||||
CustomSinkBuffer &LogGetterImpl::GetBuffer() {
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(u8, s_buffer[32_KB]);
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(CustomSinkBuffer, s_custom_sink_buffer, s_buffer, sizeof(s_buffer), FlushFunction);
|
||||
|
||||
static constinit u8 s_buffer[32_KB];
|
||||
static constinit CustomSinkBuffer s_custom_sink_buffer(s_buffer, sizeof(s_buffer), FlushFunction);
|
||||
return s_custom_sink_buffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ namespace ams::lm::srv {
|
||||
size_t carry_size;
|
||||
bool ends_with_text_log;
|
||||
};
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(PreviousPacketContext, s_previous_packet_context);
|
||||
static constinit PreviousPacketContext s_previous_packet_context = {};
|
||||
|
||||
/* Get the packet header. */
|
||||
auto *header = static_cast<const impl::LogPacketHeader *>(buffer);
|
||||
|
||||
@@ -308,7 +308,7 @@ namespace ams::ncm {
|
||||
out_orphaned[i] = true;
|
||||
}
|
||||
|
||||
auto IsOrphanedContent = [](const sf::InArray<ContentId> &list, const ncm::ContentId &id) ALWAYS_INLINE_LAMBDA -> util::optional<size_t> {
|
||||
auto IsOrphanedContent = [] ALWAYS_INLINE_LAMBDA (const sf::InArray<ContentId> &list, const ncm::ContentId &id) -> util::optional<size_t> {
|
||||
/* Check if any input content ids match our found content id. */
|
||||
for (size_t i = 0; i < list.GetSize(); i++) {
|
||||
if (list[i] == id) {
|
||||
|
||||
@@ -635,7 +635,7 @@ namespace ams::ncm {
|
||||
for (s32 i = 0; i < count; i++) {
|
||||
R_UNLESS(!this->IsCancelRequested(), ncm::ResultCreatePlaceHolderCancelled());
|
||||
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(os::SdkMutex, s_placeholder_mutex);
|
||||
static constinit os::SdkMutex s_placeholder_mutex;
|
||||
std::scoped_lock lk(s_placeholder_mutex);
|
||||
|
||||
InstallContentMeta content_meta;
|
||||
|
||||
@@ -44,8 +44,7 @@ namespace ams::ncm {
|
||||
}
|
||||
|
||||
HeapState &GetHeapState() {
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(HeapState, s_heap_state);
|
||||
|
||||
static HeapState s_heap_state = {};
|
||||
return s_heap_state;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,26 +52,6 @@ namespace ams::os::impl {
|
||||
/* Get the thread impl object from libnx. */
|
||||
ThreadImpl *thread_impl = ::threadGetSelf();
|
||||
|
||||
/* Hack around libnx's main thread, to ensure stratosphere thread type consistency. */
|
||||
{
|
||||
auto *tlr = reinterpret_cast<uintptr_t *>(svc::GetThreadLocalRegion());
|
||||
for (size_t i = sizeof(svc::ThreadLocalRegion) / sizeof(uintptr_t); i > 0; --i) {
|
||||
if (auto *candidate = reinterpret_cast<ThreadImpl *>(tlr[i - 1]); candidate == thread_impl) {
|
||||
ThreadImpl *embedded_thread = std::addressof(main_thread->thread_impl_storage);
|
||||
|
||||
*embedded_thread = *thread_impl;
|
||||
|
||||
if (embedded_thread->next) {
|
||||
embedded_thread->next->prev_next = std::addressof(embedded_thread->next);
|
||||
}
|
||||
|
||||
thread_impl = embedded_thread;
|
||||
tlr[i-1] = reinterpret_cast<uintptr_t>(thread_impl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the thread priority. */
|
||||
s32 horizon_priority;
|
||||
R_ABORT_UNLESS(svc::GetThreadPriority(std::addressof(horizon_priority), thread_impl->handle));
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace ams::osdbg::impl {
|
||||
static_assert(AMS_OFFSETOF(ThreadLocalRegionIlp32, tls) == 0x1C0);
|
||||
|
||||
struct LibnxThreadVars {
|
||||
static constexpr u32 Magic = util::ReverseFourCC<'!','T','V','$'>::Code;
|
||||
static constexpr u32 Magic = util::FourCC<'!','T','V','$'>::Code;
|
||||
|
||||
u32 magic;
|
||||
::Handle handle;
|
||||
@@ -69,11 +69,11 @@ namespace ams::osdbg::impl {
|
||||
volatile u16 disable_counter;
|
||||
volatile u16 interrupt_flag;
|
||||
u32 reserved0;
|
||||
u64 tls[(0x200 - sizeof(LibnxThreadVars) - 0x108) / sizeof(u64)];
|
||||
u64 tls[(0x1E0 - 0x108) / sizeof(u64)];
|
||||
LibnxThreadVars thread_vars;
|
||||
};
|
||||
static_assert(sizeof(ThreadLocalRegionLibnx) == sizeof(svc::ThreadLocalRegion));
|
||||
static_assert(AMS_OFFSETOF(ThreadLocalRegionLibnx, thread_vars) == 0x200 - sizeof(LibnxThreadVars));
|
||||
static_assert(AMS_OFFSETOF(ThreadLocalRegionLibnx, thread_vars) == 0x1E0);
|
||||
|
||||
struct LibnxThreadEntryArgs {
|
||||
u64 t;
|
||||
|
||||
@@ -50,9 +50,9 @@ namespace ams::osdbg {
|
||||
} else {
|
||||
/* Special-case libnx threads. */
|
||||
if (thread_info->_thread_type_type == ThreadTypeType_Libnx) {
|
||||
util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%010lx", reinterpret_cast<uintptr_t>(thread_info->_thread_type));
|
||||
util::TSNPrintf(dst, os::ThreadNameLengthMax, "libnx Thread_0x%p", reinterpret_cast<void *>(thread_info->_thread_type));
|
||||
} else {
|
||||
util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%010lx", reinterpret_cast<uintptr_t>(thread_info->_thread_type));
|
||||
util::TSNPrintf(dst, os::ThreadNameLengthMax, "Thread_0x%p", reinterpret_cast<void *>(thread_info->_thread_type));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
|
||||
@@ -20,44 +20,60 @@ namespace ams::powctl::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit os::ThreadType g_interrupt_thread;
|
||||
os::ThreadType g_interrupt_thread;
|
||||
|
||||
constexpr inline size_t InterruptThreadStackSize = os::MemoryPageSize;
|
||||
alignas(os::MemoryPageSize) u8 g_interrupt_thread_stack[InterruptThreadStackSize];
|
||||
|
||||
constinit u8 g_unit_heap_memory[2_KB];
|
||||
constinit lmem::HeapHandle g_unit_heap_handle;
|
||||
constinit sf::UnitHeapMemoryResource g_unit_heap_memory_resource;
|
||||
|
||||
IPowerControlDriver::List &GetDriverList() {
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(IPowerControlDriver::List, s_driver_list);
|
||||
static constinit IPowerControlDriver::List s_driver_list;
|
||||
return s_driver_list;
|
||||
}
|
||||
|
||||
ddsf::EventHandlerManager &GetInterruptHandlerManager() {
|
||||
AMS_FUNCTION_LOCAL_STATIC(ddsf::EventHandlerManager, s_interrupt_handler_manager);
|
||||
static constinit util::TypedStorage<ddsf::EventHandlerManager> s_interrupt_handler_manager;
|
||||
static constinit bool s_initialized = false;
|
||||
static constinit os::SdkMutex s_mutex;
|
||||
|
||||
return s_interrupt_handler_manager;
|
||||
if (AMS_UNLIKELY(!s_initialized)) {
|
||||
std::scoped_lock lk(s_mutex);
|
||||
|
||||
if (AMS_LIKELY(!s_initialized)) {
|
||||
util::ConstructAt(s_interrupt_handler_manager);
|
||||
s_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
return util::GetReference(s_interrupt_handler_manager);
|
||||
}
|
||||
|
||||
ddsf::DeviceCodeEntryManager &GetDeviceCodeEntryManager() {
|
||||
class DeviceCodeEntryManagerWithUnitHeap {
|
||||
private:
|
||||
u8 m_heap_memory[2_KB];
|
||||
sf::UnitHeapMemoryResource m_memory_resource;
|
||||
util::TypedStorage<ddsf::DeviceCodeEntryManager> m_manager;
|
||||
public:
|
||||
DeviceCodeEntryManagerWithUnitHeap() {
|
||||
/* Initialize the memory resource. */
|
||||
m_memory_resource.Attach(lmem::CreateUnitHeap(m_heap_memory, sizeof(m_heap_memory), sizeof(ddsf::DeviceCodeEntryHolder), lmem::CreateOption_ThreadSafe));
|
||||
static constinit util::TypedStorage<ddsf::DeviceCodeEntryManager> s_device_code_entry_manager;
|
||||
static constinit bool s_initialized = false;
|
||||
static constinit os::SdkMutex s_mutex;
|
||||
|
||||
/* Construct the entry manager. */
|
||||
util::ConstructAt(m_manager, std::addressof(m_memory_resource));
|
||||
}
|
||||
if (AMS_UNLIKELY(!s_initialized)) {
|
||||
std::scoped_lock lk(s_mutex);
|
||||
|
||||
ALWAYS_INLINE operator ddsf::DeviceCodeEntryManager &() {
|
||||
return util::GetReference(m_manager);
|
||||
}
|
||||
};
|
||||
AMS_FUNCTION_LOCAL_STATIC(DeviceCodeEntryManagerWithUnitHeap, s_device_code_entry_manager_holder);
|
||||
if (AMS_LIKELY(!s_initialized)) {
|
||||
/* Initialize the entry code heap. */
|
||||
g_unit_heap_handle = lmem::CreateUnitHeap(g_unit_heap_memory, sizeof(g_unit_heap_memory), sizeof(ddsf::DeviceCodeEntryHolder), lmem::CreateOption_ThreadSafe);
|
||||
|
||||
return s_device_code_entry_manager_holder;
|
||||
/* Initialize the entry code memory resource. */
|
||||
g_unit_heap_memory_resource.Attach(g_unit_heap_handle);
|
||||
|
||||
/* Make the entry manager using the newly initialized memory resource. */
|
||||
util::ConstructAt(s_device_code_entry_manager, std::addressof(g_unit_heap_memory_resource));
|
||||
|
||||
s_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
return util::GetReference(s_device_code_entry_manager);
|
||||
}
|
||||
|
||||
void InterruptThreadFunction(void *arg) {
|
||||
|
||||
@@ -24,14 +24,25 @@ namespace ams::pwm::driver::impl {
|
||||
constinit int g_init_count = 0;
|
||||
|
||||
pwm::driver::IPwmDriver::List &GetPwmDriverList() {
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(pwm::driver::IPwmDriver::List, s_driver_list);
|
||||
static constinit pwm::driver::IPwmDriver::List s_driver_list;
|
||||
return s_driver_list;
|
||||
}
|
||||
|
||||
ddsf::DeviceCodeEntryManager &GetDeviceCodeEntryManager() {
|
||||
AMS_FUNCTION_LOCAL_STATIC(ddsf::DeviceCodeEntryManager, s_device_code_entry_manager, ddsf::GetDeviceCodeEntryHolderMemoryResource());
|
||||
static constinit util::TypedStorage<ddsf::DeviceCodeEntryManager> s_device_code_entry_manager;
|
||||
static constinit bool s_initialized = false;
|
||||
static constinit os::SdkMutex s_mutex;
|
||||
|
||||
return s_device_code_entry_manager;
|
||||
if (AMS_UNLIKELY(!s_initialized)) {
|
||||
std::scoped_lock lk(s_mutex);
|
||||
|
||||
if (AMS_LIKELY(!s_initialized)) {
|
||||
util::ConstructAt(s_device_code_entry_manager, ddsf::GetDeviceCodeEntryHolderMemoryResource());
|
||||
s_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
return util::GetReference(s_device_code_entry_manager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -289,8 +289,14 @@ namespace ams::settings::impl {
|
||||
}
|
||||
|
||||
lmem::HeapHandle &GetHeapHandle() {
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(u8, s_heap_memory[HeapMemorySize]);
|
||||
AMS_FUNCTION_LOCAL_STATIC(lmem::HeapHandle, s_heap_handle, lmem::CreateExpHeap(s_heap_memory, sizeof(s_heap_memory), lmem::CreateOption_ThreadSafe));
|
||||
static constinit bool s_is_initialized = false;
|
||||
static constinit lmem::HeapHandle s_heap_handle;
|
||||
static constinit u8 s_heap_memory[HeapMemorySize];
|
||||
|
||||
if (!s_is_initialized) {
|
||||
s_heap_handle = lmem::CreateExpHeap(s_heap_memory, sizeof(s_heap_memory), lmem::CreateOption_None);
|
||||
s_is_initialized = true;
|
||||
}
|
||||
|
||||
return s_heap_handle;
|
||||
}
|
||||
@@ -308,15 +314,24 @@ namespace ams::settings::impl {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
/* Declare static instance variables. */
|
||||
AMS_FUNCTION_LOCAL_STATIC(Map, s_map);
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_is_map_loaded, false);
|
||||
static constinit util::TypedStorage<Map> s_storage = {};
|
||||
static constinit bool s_is_initialized = false;
|
||||
static constinit bool s_is_loaded = false;
|
||||
|
||||
/* Get pointer to the map. */
|
||||
Map * const map = std::addressof(s_map);
|
||||
Map *map = util::GetPointer(s_storage);
|
||||
|
||||
/* Construct the map, if we haven't already. */
|
||||
if (AMS_UNLIKELY(!s_is_initialized)) {
|
||||
/* Construct the instance. */
|
||||
util::ConstructAt(s_storage);
|
||||
|
||||
/* Note that we constructed. */
|
||||
s_is_initialized = true;
|
||||
}
|
||||
|
||||
/* TODO: Mutex? */
|
||||
/* Load the map, if we haven't already. */
|
||||
if (AMS_UNLIKELY(!s_is_map_loaded)) {
|
||||
if (AMS_UNLIKELY(!s_is_loaded)) {
|
||||
/* Attempt to load the map, allowing for failure if acceptable. */
|
||||
const auto result = LoadKeyValueStoreMap(map);
|
||||
|
||||
@@ -325,7 +340,7 @@ namespace ams::settings::impl {
|
||||
}
|
||||
|
||||
/* Note that the map is loaded. */
|
||||
s_is_map_loaded = true;
|
||||
s_is_loaded = true;
|
||||
}
|
||||
|
||||
/* Set the output pointer. */
|
||||
@@ -410,13 +425,26 @@ namespace ams::settings::impl {
|
||||
AMS_ASSERT(out_data != nullptr);
|
||||
|
||||
/* Declare static instance variables. */
|
||||
AMS_FUNCTION_LOCAL_STATIC(SystemData, s_data, id, GetSystemDataMountName<T>());
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_mounted, false);
|
||||
static constinit util::TypedStorage<SystemData> s_storage = {};
|
||||
static constinit bool s_initialized = false;
|
||||
static constinit bool s_mounted = false;
|
||||
|
||||
/* Get pointer to the system data. */
|
||||
SystemData *data = std::addressof(s_data);
|
||||
SystemData *data = util::GetPointer(s_storage);
|
||||
|
||||
/* Construct the system data, if we haven't already. */
|
||||
if (AMS_UNLIKELY(!s_initialized)) {
|
||||
/* Construct the instance. */
|
||||
util::ConstructAt(s_storage);
|
||||
|
||||
/* Setup system data. */
|
||||
data->SetSystemDataId(id);
|
||||
data->SetMountName(GetSystemDataMountName<T>());
|
||||
|
||||
/* Note that we constructed. */
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
/* TODO: Mutex? */
|
||||
/* Mount the system data, if we haven't already. */
|
||||
if (AMS_UNLIKELY(!s_mounted)) {
|
||||
/* Mount the system data. */
|
||||
@@ -436,11 +464,28 @@ namespace ams::settings::impl {
|
||||
AMS_ASSERT(out_data != nullptr);
|
||||
|
||||
/* Declare static instance variables. */
|
||||
AMS_FUNCTION_LOCAL_STATIC(SystemSaveData, s_data, SystemSaveDataId, SystemSaveDataSize, SystemSaveDataJournalSize, SystemSaveDataFlags, SystemSaveDataMountName);
|
||||
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_mounted, false);
|
||||
static constinit util::TypedStorage<SystemSaveData> s_storage = {};
|
||||
static constinit bool s_initialized = false;
|
||||
static constinit bool s_mounted = false;
|
||||
|
||||
/* Get pointer to the system save data. */
|
||||
SystemSaveData *data = std::addressof(s_data);
|
||||
/* Get pointer to the system data. */
|
||||
SystemSaveData *data = util::GetPointer(s_storage);
|
||||
|
||||
/* Construct the system data, if we haven't already. */
|
||||
if (AMS_UNLIKELY(!s_initialized)) {
|
||||
/* Construct the instance. */
|
||||
util::ConstructAt(s_storage);
|
||||
|
||||
/* Setup system data. */
|
||||
data->SetSystemSaveDataId(SystemSaveDataId);
|
||||
data->SetTotalSize(SystemSaveDataSize);
|
||||
data->SetJournalSize(SystemSaveDataJournalSize);
|
||||
data->SetFlags(SystemSaveDataFlags);
|
||||
data->SetMountName(SystemSaveDataMountName);
|
||||
|
||||
/* Note that we constructed. */
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
/* Mount the system data, if we haven't already. */
|
||||
if (AMS_UNLIKELY(!s_mounted)) {
|
||||
|
||||
@@ -56,33 +56,27 @@ namespace ams::settings::impl {
|
||||
}
|
||||
|
||||
SplConfig GetSplConfig() {
|
||||
class SplConfigHolder {
|
||||
NON_COPYABLE(SplConfigHolder);
|
||||
NON_MOVEABLE(SplConfigHolder);
|
||||
private:
|
||||
SplConfig m_config;
|
||||
public:
|
||||
SplConfigHolder() {
|
||||
/* Initialize spl. */
|
||||
spl::Initialize();
|
||||
ON_SCOPE_EXIT { spl::Finalize(); };
|
||||
static constinit bool s_is_initialized = false;
|
||||
static constinit SplConfig s_config;
|
||||
|
||||
/* Create the config. */
|
||||
m_config = {
|
||||
.is_development = spl::IsDevelopment(),
|
||||
.hardware_type = ConvertToSplHardwareType(spl::GetHardwareType()),
|
||||
.is_quest = IsSplRetailInteractiveDisplayStateEnabled(spl::GetRetailInteractiveDisplayState()),
|
||||
.device_id_low = spl::GetDeviceIdLow(),
|
||||
};
|
||||
}
|
||||
if (!s_is_initialized) {
|
||||
/* Initialize spl. */
|
||||
spl::Initialize();
|
||||
ON_SCOPE_EXIT { spl::Finalize(); };
|
||||
|
||||
ALWAYS_INLINE operator SplConfig() {
|
||||
return m_config;
|
||||
}
|
||||
};
|
||||
/* Create the config. */
|
||||
s_config = {
|
||||
.is_development = spl::IsDevelopment(),
|
||||
.hardware_type = ConvertToSplHardwareType(spl::GetHardwareType()),
|
||||
.is_quest = IsSplRetailInteractiveDisplayStateEnabled(spl::GetRetailInteractiveDisplayState()),
|
||||
.device_id_low = spl::GetDeviceIdLow(),
|
||||
};
|
||||
|
||||
AMS_FUNCTION_LOCAL_STATIC(SplConfigHolder, s_config_holder);
|
||||
return s_config_holder;
|
||||
/* Mark as initialized. */
|
||||
s_is_initialized = true;
|
||||
}
|
||||
|
||||
return s_config;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user