Compare commits

..

2 Commits

Author SHA1 Message Date
Michael Scire
dc52da2819 kern: simplify rela-in-bss impl 2021-10-08 12:46:23 -07:00
Michael Scire
cfc54dbc88 kern: put rela in bss (EXPERIMENTAL)
NOTE: This does some really gross things. It saves ~0x4000 of space, but
at the cost of crimes against the linker script. We should consider/evaluate
whether this is worth doing for real.
2021-10-08 12:32:35 -07:00
971 changed files with 18405 additions and 34415 deletions

4
.gitignore vendored
View File

@@ -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

View File

@@ -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

View File

@@ -7,7 +7,6 @@ Building Atmosphère is a very straightforward process that relies almost exclus
+ [Python 2](https://www.python.org) (Python 3 may work as well, but this is not guaranteed)
+ [LZ4](https://pypi.org/project/lz4)
+ [PyCryptodome](https://pypi.org/project/pycryptodome) (optional)
+ [hactool](https://github.com/SciresM/hactool)
## Instructions
1. Follow the guide located [here](https://devkitpro.org/wiki/Getting_Started) to install and configure all the tools necessary for the build process.
@@ -18,7 +17,6 @@ Building Atmosphère is a very straightforward process that relies almost exclus
+ `switch-libjpeg-turbo`
+ `devkitARM`
+ `devkitarm-rules`
+ `hactool`
3. Install the following library via python's package manager `pip`, required by [exosphere](components/exosphere.md):
+ `lz4`

View File

@@ -1,140 +1,4 @@
# Changelog
## 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.
+ The "target firmware" system was changed to allow the bootloader to specify an approximation, rather than the true target firmware.
+ Previously we expected compliant bootloaders to inspect SYSTEM:/ to determine the specific target firmware.
+ Now, we only require an approximate version, with major version == true major version and approximate version <= true version.
+ This greatly simplifies bootloader requirements, and correspondingly all code for accessing SYSTEM has been removed from fusee.
+ This should result in a substantial speedup when booting emummc with fusee, as SYSTEM accesses were the most expensive thing done previously.
+ This should resolve any inconsistency in firmware detection when booting via fusee vs hekate.
+ This should also improve our compatibility with micro firmware releases, making it more likely that atmosphere "just works" if nothing important has changed.
+ Dynamic resource limit determination logic was implemented in `pm` to match latest official behavior.
+ This greatly simplifies/makes consistent the resource limits on older firmwares, as well.
+ An enormous amount of refactoring was performed under the hood, including:
+ **Please Note**: If you are a developer who uses Atmosphere-libs, a number of changes here are breaking.
+ Feel free to contact SciresM#0524 for help updating your program.
+ The OS namespace had many primitives implemented/made more accurate.
+ Since mesosphere is now always-on, os::LightEvent (which required newer SVCs) is now globally usable (and used by stratosphere where relevant).
+ Assertions are now true no-ops when building for release.
+ Stratosphere is now built with -Wextra/-Werror.
+ Most "common" logic in system module main.cpp files was moved into libstratosphere.
+ **Please Note**: main.cpp files for prior atmosphere-libs will no longer work, for a really large number of reasons.
+ A number of longstanding code style issues were corrected.
+ Mesosphere now uses util::BitFlagSet for SVC permissions.
+ Mesosphere now puts its relocation table inside .bss, which allows that memory to be reclaimed after relocations are performed.
+ These changes save ~16KB of memory in the kernel, all said and done.
+ A number of locations in stratosphere where memory could be saved were spotted and taken advantage of, leading to ~150-200KB of saved memory.
+ The `spl` and `loader` system module was refactored to better reflect official logic.
+ `sf` ipc server code was updated to only emit mitm/defer logic when that logic is actually required somewhere in process.
+ `tipc` ipc server code was updated to reflect changes to official logic made in 13.0.0.
+ Many, many other minor changes, please talk to SciresM#0524 or read the relevant commits if you want to know more.
+ A number of minor issues were fixed, including:
+ Mesosphere's handling of SVC permissions on thread pin/unpin was updated to reflect official kernel behavior.
+ util::CountTrailingZeroes() was fixed to calculate the correct value when used at compile-time.
+ General system stability improvements to enhance the user's experience.
## 1.1.1
+ A bug was fixed which caused some memory to leak when launching a game with mods enabled, eventually causing a crash after enough game launches without rebooting.
+ General system stability improvements to enhance the user's experience.

6
emummc/.gitrepo vendored
View File

@@ -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
View File

@@ -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

View File

@@ -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);
}

View File

@@ -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,
};

View File

@@ -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__

View File

@@ -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__

View File

@@ -22,14 +22,14 @@ namespace ams::secmon::loader {
class Lz4Uncompressor {
private:
const u8 *m_src;
size_t m_src_size;
size_t m_src_offset;
u8 *m_dst;
size_t m_dst_size;
size_t m_dst_offset;
const u8 *src;
size_t src_size;
size_t src_offset;
u8 *dst;
size_t dst_size;
size_t dst_offset;
public:
Lz4Uncompressor(void *dst, size_t dst_size, const void *src, size_t src_size) : m_src(static_cast<const u8 *>(src)), m_src_size(src_size), m_src_offset(0), m_dst(static_cast<u8 *>(dst)), m_dst_size(dst_size), m_dst_offset(0) {
Lz4Uncompressor(void *dst, size_t dst_size, const void *src, size_t src_size) : src(static_cast<const u8 *>(src)), src_size(src_size), src_offset(0), dst(static_cast<u8 *>(dst)), dst_size(dst_size), dst_offset(0) {
/* ... */
}
@@ -42,7 +42,7 @@ namespace ams::secmon::loader {
this->Copy(this->GetCopySize(control >> 4));
/* If we've exceeded size, we're done. */
if (m_src_offset >= m_src_size) {
if (this->src_offset >= this->src_size) {
break;
}
@@ -55,21 +55,21 @@ namespace ams::secmon::loader {
const size_t wide_copy_size = this->GetCopySize(control & 0xF);
/* Copy bytes. */
const size_t end_offset = m_dst_offset + wide_copy_size + 4;
for (size_t cur_offset = m_dst_offset; cur_offset < end_offset; m_dst_offset = (++cur_offset)) {
const size_t end_offset = this->dst_offset + wide_copy_size + 4;
for (size_t cur_offset = this->dst_offset; cur_offset < end_offset; this->dst_offset = (++cur_offset)) {
AMS_ABORT_UNLESS(wide_offset <= cur_offset);
m_dst[cur_offset] = m_dst[cur_offset - wide_offset];
this->dst[cur_offset] = this->dst[cur_offset - wide_offset];
}
}
}
private:
u8 ReadByte() {
return m_src[m_src_offset++];
return this->src[this->src_offset++];
}
bool CanRead() const {
return m_src_offset < m_src_size;
return this->src_offset < this->src_size;
}
size_t GetCopySize(u8 control) {
@@ -87,9 +87,9 @@ namespace ams::secmon::loader {
}
void Copy(size_t size) {
__builtin_memcpy(m_dst + m_dst_offset, m_src + m_src_offset, size);
m_dst_offset += size;
m_src_offset += size;
__builtin_memcpy(this->dst + this->dst_offset, this->src + this->src_offset, size);
this->dst_offset += size;
this->src_offset += size;
}
};

View File

@@ -76,10 +76,10 @@ namespace ams::secmon::fatal {
Bit_Readable = 31,
};
private:
u32 m_value;
u32 value;
protected:
constexpr ALWAYS_INLINE u32 SelectBit(Bit n) const {
return (m_value & (1u << n));
return (this->value & (1u << n));
}
constexpr ALWAYS_INLINE bool GetBit(Bit n) const {
@@ -97,7 +97,7 @@ namespace ams::secmon::fatal {
ALWAYS_INLINE void SetValue(u32 v) {
/* Prevent re-ordering around entry modifications. */
__asm__ __volatile__("" ::: "memory");
m_value = v;
this->value = v;
__asm__ __volatile__("" ::: "memory");
}
public:
@@ -112,7 +112,7 @@ namespace ams::secmon::fatal {
constexpr ALWAYS_INLINE u32 GetAttributes() const { return this->SelectBit(Bit_NonSecure) | this->SelectBit(Bit_Writeable) | this->SelectBit(Bit_Readable); }
constexpr ALWAYS_INLINE dd::PhysicalAddress GetPhysicalAddress() const { return (static_cast<u64>(m_value) << DevicePageBits) & PhysicalAddressMask; }
constexpr ALWAYS_INLINE dd::PhysicalAddress GetPhysicalAddress() const { return (static_cast<u64>(this->value) << DevicePageBits) & PhysicalAddressMask; }
ALWAYS_INLINE void Invalidate() { this->SetValue(0); }
};

View File

@@ -221,7 +221,7 @@ namespace ams::secmon::fatal {
const int prefix_len = std::strlen(automatic_backups_prefix);
for (size_t i = 0; i + prefix_len < f_ctx->stack_dump_size; ++i) {
if (std::memcmp(f_ctx->stack_dump + i, automatic_backups_prefix, prefix_len) == 0) {
if (std::memcmp(&f_ctx->stack_dump[i], automatic_backups_prefix, prefix_len) == 0) {
suggestion = "The atmosphere directory may improperly have archive bits set.\n"
"Please try running an archive bit fixer tool (for example, the one in Hekate).\n";
break;

View File

@@ -28,7 +28,7 @@ namespace ams::fs {
};
struct ReadOption {
u32 _value;
u32 value;
static const ReadOption None;
};
@@ -36,7 +36,7 @@ namespace ams::fs {
inline constexpr const ReadOption ReadOption::None = {0};
inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) {
return lhs._value == rhs._value;
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) {
@@ -46,10 +46,10 @@ namespace ams::fs {
static_assert(util::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32));
struct WriteOption {
u32 _value;
u32 value;
constexpr inline bool HasFlushFlag() const {
return _value & 1;
return this->value & 1;
}
static const WriteOption None;
@@ -60,7 +60,7 @@ namespace ams::fs {
inline constexpr const WriteOption WriteOption::Flush = {1};
inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) {
return lhs._value == rhs._value;
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) {

View File

@@ -22,7 +22,7 @@ namespace ams::secmon {
constexpr inline uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress();
constinit util::Atomic<bool> g_is_locked = false;
constinit std::atomic_bool g_is_locked = false;
}
@@ -72,7 +72,7 @@ namespace ams::secmon {
}
/* Acquire exclusive access to exception handling logic. */
if (!g_is_locked.Exchange(true)) {
if (!g_is_locked.exchange(true)) {
/* Invoke the exception handler impl. */
ExceptionHandlerImpl(lr, sp);

View File

@@ -23,16 +23,16 @@ namespace ams::secmon {
void *PageMapperImpl::GetPointerTo(uintptr_t phys, size_t size) const {
/* Ensure we stay within the page. */
if (util::AlignDown(phys, 4_KB) != m_physical_address) {
if (util::AlignDown(phys, 4_KB) != this->physical_address) {
return nullptr;
}
if (size != 0) {
if (util::AlignDown(phys + size - 1, 4_KB) != m_physical_address) {
if (util::AlignDown(phys + size - 1, 4_KB) != this->physical_address) {
return nullptr;
}
}
return reinterpret_cast<void *>(phys + (m_virtual_address - m_physical_address));
return reinterpret_cast<void *>(phys + (this->virtual_address - this->physical_address));
}
bool PageMapperImpl::CopyToMapping(uintptr_t dst_phys, const void *src, size_t size) const {

View File

@@ -22,10 +22,10 @@ namespace ams::secmon {
class PageMapperImpl {
private:
uintptr_t m_physical_address;
uintptr_t m_virtual_address;
uintptr_t physical_address;
uintptr_t virtual_address;
public:
constexpr PageMapperImpl(uintptr_t phys) : m_physical_address(util::AlignDown(phys, 4_KB)), m_virtual_address() { /* ... */ }
constexpr PageMapperImpl(uintptr_t phys) : physical_address(util::AlignDown(phys, 4_KB)), virtual_address() { /* ... */ }
void *GetPointerTo(uintptr_t phys, size_t size) const;
@@ -37,14 +37,14 @@ namespace ams::secmon {
template<auto F>
bool MapImpl() {
m_virtual_address = F(m_physical_address);
return m_virtual_address != 0;
this->virtual_address = F(this->physical_address);
return this->virtual_address != 0;
}
template<auto F>
void UnmapImpl() {
F();
m_virtual_address = 0;
this->virtual_address = 0;
}
};

View File

@@ -417,7 +417,7 @@ namespace ams::secmon::smc {
case CipherMode_CbcDecryption: se::DecryptAes128CbcAsync(output_address, slot, input_address, size, iv, sizeof(iv), SecurityEngineDoneHandler); break;
case CipherMode_Ctr: se::ComputeAes128CtrAsync(output_address, slot, input_address, size, iv, sizeof(iv), SecurityEngineDoneHandler); break;
case CipherMode_Cmac:
return SmcResult::NotSupported;
return SmcResult::NotImplemented;
default:
return SmcResult::InvalidArgument;
}
@@ -765,8 +765,8 @@ namespace ams::secmon::smc {
const auto which = static_cast<SecureData>(args.r[1]);
/* Validate arguments/conditions. */
SMC_R_UNLESS(fuse::GetPatchVersion() < fuse::PatchVersion_Odnx02A2, NotSupported);
SMC_R_UNLESS(which < SecureData_Count, NotSupported);
SMC_R_UNLESS(fuse::GetPatchVersion() < fuse::PatchVersion_Odnx02A2, NotImplemented);
SMC_R_UNLESS(which < SecureData_Count, NotImplemented);
/* Use a temporary buffer. */
u8 secure_data[AesKeySize];

View File

@@ -20,7 +20,7 @@ namespace ams::secmon::smc {
enum class SmcResult : u32 {
Success = 0,
NotSupported = 1,
NotImplemented = 1,
InvalidArgument = 2,
Busy = 3,
NoAsyncOperation = 4,

View File

@@ -164,7 +164,6 @@ namespace ams::secmon::smc {
}
constinit u64 g_payload_address = 0;
constinit bool g_set_true_target_firmware = false;
SmcResult GetConfig(SmcArguments &args, bool kern) {
switch (static_cast<ConfigItem>(args.r[1])) {
@@ -214,8 +213,8 @@ namespace ams::secmon::smc {
case ConfigItem::IsChargerHiZModeEnabled:
args.r[1] = IsChargerHiZModeEnabled();
break;
case ConfigItem::RetailInteractiveDisplayState:
args.r[1] = fuse::GetRetailInteractiveDisplayState();
case ConfigItem::QuestState:
args.r[1] = fuse::GetQuestState();
break;
case ConfigItem::RegulatorType:
args.r[1] = fuse::GetRegulator();
@@ -241,15 +240,11 @@ namespace ams::secmon::smc {
break;
case ConfigItem::ExosphereApiVersion:
/* Get information about the current exosphere version. */
if (kern || g_set_true_target_firmware) {
args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) |
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) |
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) |
(static_cast<u64>(GetKeyGeneration()) << 32) |
(static_cast<u64>(GetTargetFirmware()) << 0);
} else {
return SmcResult::NotInitialized;
}
args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) |
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) |
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) |
(static_cast<u64>(GetKeyGeneration()) << 32) |
(static_cast<u64>(GetTargetFirmware()) << 0);
break;
case ConfigItem::ExosphereNeedsReboot:
/* We are executing, so we aren't in the process of rebooting. */
@@ -302,18 +297,6 @@ namespace ams::secmon::smc {
(static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR & 0xFF) << 16) |
(static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO & 0xFF) << 8);
break;
case ConfigItem::ExosphereApproximateApiVersion:
/* Get information about the current exosphere version. */
if (!g_set_true_target_firmware) {
args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) |
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) |
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) |
(static_cast<u64>(GetKeyGeneration()) << 32) |
(static_cast<u64>(GetTargetFirmware()) << 0);
} else {
return SmcResult::Busy;
}
break;
default:
return SmcResult::InvalidArgument;
}
@@ -329,14 +312,6 @@ namespace ams::secmon::smc {
/* Configure the HiZ mode. */
SetChargerHiZModeEnabled(static_cast<bool>(args.r[3]));
break;
case ConfigItem::ExosphereApiVersion:
if (!g_set_true_target_firmware) {
::ams::secmon::impl::SetTargetFirmware(static_cast<ams::TargetFirmware>(args.r[3] & 0xFFFFFFFF));
g_set_true_target_firmware = true;
} else {
return SmcResult::Busy;
}
break;
case ConfigItem::ExosphereNeedsReboot:
if (soc_type == fuse::SocType_Erista) {
switch (static_cast<UserRebootType>(args.r[3])) {
@@ -370,7 +345,7 @@ namespace ams::secmon::smc {
PerformUserShutDown();
}
} else /* if (soc_type == fuse::SocType_Mariko) */ {
return SmcResult::NotSupported;
return SmcResult::NotImplemented;
}
break;
case ConfigItem::ExospherePayloadAddress:
@@ -414,7 +389,7 @@ namespace ams::secmon::smc {
/* Validate arguments. */
/* NOTE: In the future, configuration for non-NAND storage may be implemented. */
SMC_R_UNLESS(mmc == EmummcMmc_Nand, NotSupported);
SMC_R_UNLESS(mmc == EmummcMmc_Nand, NotImplemented);
SMC_R_UNLESS(user_offset + 2 * sizeof(EmummcFilePath) <= 4_KB, InvalidArgument);
/* Get the emummc config. */

View File

@@ -34,25 +34,24 @@ namespace ams::secmon::smc {
IsDevelopmentFunctionEnabled = 11,
KernelConfiguration = 12,
IsChargerHiZModeEnabled = 13,
RetailInteractiveDisplayState = 14,
QuestState = 14,
RegulatorType = 15,
DeviceUniqueKeyGeneration = 16,
Package2Hash = 17,
/* Extension config items for exosphere. */
ExosphereApiVersion = 65000,
ExosphereNeedsReboot = 65001,
ExosphereNeedsShutdown = 65002,
ExosphereGitCommitHash = 65003,
ExosphereHasRcmBugPatch = 65004,
ExosphereBlankProdInfo = 65005,
ExosphereAllowCalWrites = 65006,
ExosphereEmummcType = 65007,
ExospherePayloadAddress = 65008,
ExosphereLogConfiguration = 65009,
ExosphereForceEnableUsb30 = 65010,
ExosphereSupportedHosVersion = 65011,
ExosphereApproximateApiVersion = 65012,
ExosphereApiVersion = 65000,
ExosphereNeedsReboot = 65001,
ExosphereNeedsShutdown = 65002,
ExosphereGitCommitHash = 65003,
ExosphereHasRcmBugPatch = 65004,
ExosphereBlankProdInfo = 65005,
ExosphereAllowCalWrites = 65006,
ExosphereEmummcType = 65007,
ExospherePayloadAddress = 65008,
ExosphereLogConfiguration = 65009,
ExosphereForceEnableUsb30 = 65010,
ExosphereSupportedHosVersion = 65011,
};
SmcResult SmcGetConfigUser(SmcArguments &args);

View File

@@ -70,7 +70,7 @@ namespace ams::secmon::smc {
SmcResult SmcWriteAddress(SmcArguments &args) {
/* NOTE: This smc was deprecated in Atmosphère 0.13.0. */
AMS_UNUSED(args);
return SmcResult::NotSupported;
return SmcResult::NotImplemented;
}
}

View File

@@ -55,31 +55,31 @@ namespace ams::secmon::smc {
class PrepareEsDeviceUniqueKeyAsyncArguments {
private:
int m_generation;
EsCommonKeyType m_type;
u8 m_label_digest[crypto::Sha256Generator::HashSize];
int generation;
EsCommonKeyType type;
u8 label_digest[crypto::Sha256Generator::HashSize];
public:
void Set(int gen, EsCommonKeyType t, const u8 ld[crypto::Sha256Generator::HashSize]) {
m_generation = gen;
m_type = t;
std::memcpy(m_label_digest, ld, sizeof(m_label_digest));
this->generation = gen;
this->type = t;
std::memcpy(this->label_digest, ld, sizeof(this->label_digest));
}
int GetKeyGeneration() const { return m_generation; }
EsCommonKeyType GetCommonKeyType() const { return m_type; }
void GetLabelDigest(u8 dst[crypto::Sha256Generator::HashSize]) const { std::memcpy(dst, m_label_digest, sizeof(m_label_digest)); }
int GetKeyGeneration() const { return this->generation; }
EsCommonKeyType GetCommonKeyType() const { return this->type; }
void GetLabelDigest(u8 dst[crypto::Sha256Generator::HashSize]) const { std::memcpy(dst, this->label_digest, sizeof(this->label_digest)); }
};
class ModularExponentiateByStorageKeyAsyncArguments {
private:
u8 m_msg[se::RsaSize];
u8 msg[se::RsaSize];
public:
void Set(const void *m, size_t m_size) {
AMS_UNUSED(m_size);
std::memcpy(m_msg, m, sizeof(m_msg));
std::memcpy(this->msg, m, sizeof(this->msg));
}
const u8 *GetMessage() const { return m_msg; }
const u8 *GetMessage() const { return this->msg; }
};
constinit SmcResult g_exp_mod_result = SmcResult::Success;

View File

@@ -21,47 +21,35 @@ namespace ams::secmon::smc {
namespace {
constinit util::Atomic<bool> g_is_locked = false;
ALWAYS_INLINE bool TryLockSecurityEngineImpl() {
bool value = false;
return g_is_locked.CompareExchangeStrong(value, true);
}
ALWAYS_INLINE void UnlockSecurityEngineImpl() {
g_is_locked = false;
}
ALWAYS_INLINE bool IsSecurityEngineLockedImpl() {
return g_is_locked.Load();
}
constinit std::atomic_bool g_is_locked = false;
}
bool TryLockSecurityEngine() {
return TryLockSecurityEngineImpl();
bool value = false;
return g_is_locked.compare_exchange_strong(value, true);
}
void UnlockSecurityEngine() {
return UnlockSecurityEngineImpl();
g_is_locked = false;
}
bool IsSecurityEngineLocked() {
return IsSecurityEngineLockedImpl();
return g_is_locked;
}
SmcResult LockSecurityEngineAndInvoke(SmcArguments &args, SmcHandler impl) {
/* Try to lock the security engine. */
SMC_R_UNLESS(TryLockSecurityEngineImpl(), Busy);
ON_SCOPE_EXIT { UnlockSecurityEngineImpl(); };
SMC_R_UNLESS(TryLockSecurityEngine(), Busy);
ON_SCOPE_EXIT { UnlockSecurityEngine(); };
return impl(args);
}
SmcResult LockSecurityEngineAndInvokeAsync(SmcArguments &args, SmcHandler impl, GetResultHandler result_handler) {
/* Try to lock the security engine. */
SMC_R_UNLESS(TryLockSecurityEngineImpl(), Busy);
auto se_guard = SCOPE_GUARD { UnlockSecurityEngineImpl(); };
SMC_R_UNLESS(TryLockSecurityEngine(), Busy);
auto se_guard = SCOPE_GUARD { UnlockSecurityEngine(); };
/* Try to start an async operation. */
const u64 async_key = BeginAsyncOperation(result_handler);

View File

@@ -73,7 +73,6 @@ SECTIONS
fusee_loader_main.o(.text*)
fusee_loader_uncompress.o(.text*)
fusee_loader_error.o(.text*)
*(.text.memcpy)
fusee_loader_main.o(.rodata*)
fusee_loader_uncompress.o(.rodata*)
fusee_loader_error.o(.rodata*)

View File

@@ -22,14 +22,14 @@ namespace ams::nxboot::loader {
class Lz4Uncompressor {
private:
const u8 *m_src;
size_t m_src_size;
size_t m_src_offset;
u8 *m_dst;
size_t m_dst_size;
size_t m_dst_offset;
const u8 *src;
size_t src_size;
size_t src_offset;
u8 *dst;
size_t dst_size;
size_t dst_offset;
public:
Lz4Uncompressor(void *dst, size_t dst_size, const void *src, size_t src_size) : m_src(static_cast<const u8 *>(src)), m_src_size(src_size), m_src_offset(0), m_dst(static_cast<u8 *>(dst)), m_dst_size(dst_size), m_dst_offset(0) {
Lz4Uncompressor(void *dst, size_t dst_size, const void *src, size_t src_size) : src(static_cast<const u8 *>(src)), src_size(src_size), src_offset(0), dst(static_cast<u8 *>(dst)), dst_size(dst_size), dst_offset(0) {
/* ... */
}
@@ -42,7 +42,7 @@ namespace ams::nxboot::loader {
this->Copy(this->GetCopySize(control >> 4));
/* If we've exceeded size, we're done. */
if (m_src_offset >= m_src_size) {
if (this->src_offset >= this->src_size) {
break;
}
@@ -55,21 +55,21 @@ namespace ams::nxboot::loader {
const size_t wide_copy_size = this->GetCopySize(control & 0xF);
/* Copy bytes. */
const size_t end_offset = m_dst_offset + wide_copy_size + 4;
for (size_t cur_offset = m_dst_offset; cur_offset < end_offset; m_dst_offset = (++cur_offset)) {
const size_t end_offset = this->dst_offset + wide_copy_size + 4;
for (size_t cur_offset = this->dst_offset; cur_offset < end_offset; this->dst_offset = (++cur_offset)) {
AMS_ABORT_UNLESS(wide_offset <= cur_offset);
m_dst[cur_offset] = m_dst[cur_offset - wide_offset];
this->dst[cur_offset] = this->dst[cur_offset - wide_offset];
}
}
}
private:
u8 ReadByte() {
return m_src[m_src_offset++];
return this->src[this->src_offset++];
}
bool CanRead() const {
return m_src_offset < m_src_size;
return this->src_offset < this->src_size;
}
size_t GetCopySize(u8 control) {
@@ -87,9 +87,11 @@ namespace ams::nxboot::loader {
}
void Copy(size_t size) {
__builtin_memcpy(m_dst + m_dst_offset, m_src + m_src_offset, size);
m_dst_offset += size;
m_src_offset += size;
for (size_t i = 0; i < size; ++i) {
this->dst[this->dst_offset + i] = this->src[this->src_offset + i];
}
this->dst_offset += size;
this->src_offset += size;
}
};

View File

@@ -27,7 +27,7 @@ bool diskio_write_sd_card(size_t sector_index, size_t sector_count, const void *
}
bool diskio_read_system(void *dst, size_t size, size_t sector_index, size_t sector_count) {
return false;
return R_SUCCEEDED(::ams::nxboot::ReadSystem(sector_index * 0x200, dst, size));
}
bool diskio_write_system(size_t sector_index, size_t sector_count, const void *src, size_t size) {

View File

@@ -27,8 +27,10 @@ namespace ams::fs {
constexpr size_t MaxDirectories = 2;
constinit bool g_is_sd_mounted = false;
constinit bool g_is_sys_mounted = false;
alignas(0x10) constinit FATFS g_sd_fs = {};
alignas(0x10) constinit FATFS g_sys_fs = {};
alignas(0x10) constinit FIL g_files[MaxFiles] = {};
alignas(0x10) constinit DIR g_dirs[MaxDirectories] = {};
@@ -129,6 +131,18 @@ namespace ams::fs {
g_is_sd_mounted = false;
}
bool MountSystem() {
AMS_ASSERT(!g_is_sys_mounted);
g_is_sys_mounted = f_mount(std::addressof(g_sys_fs), "sys:", 1) == FR_OK;
return g_is_sys_mounted;
}
void UnmountSystem() {
AMS_ASSERT(g_is_sys_mounted);
f_unmount("sys:");
g_is_sys_mounted = false;
}
Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path) {
/* Get the file info. */
FILINFO info;

View File

@@ -28,7 +28,7 @@ namespace ams::fs {
};
struct ReadOption {
u32 _value;
u32 value;
static const ReadOption None;
};
@@ -36,7 +36,7 @@ namespace ams::fs {
inline constexpr const ReadOption ReadOption::None = {0};
inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) {
return lhs._value == rhs._value;
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const ReadOption &lhs, const ReadOption &rhs) {
@@ -46,10 +46,10 @@ namespace ams::fs {
static_assert(util::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32));
struct WriteOption {
u32 _value;
u32 value;
constexpr inline bool HasFlushFlag() const {
return _value & 1;
return this->value & 1;
}
static const WriteOption None;
@@ -60,7 +60,7 @@ namespace ams::fs {
inline constexpr const WriteOption WriteOption::Flush = {1};
inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) {
return lhs._value == rhs._value;
return lhs.value == rhs.value;
}
inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) {
@@ -98,6 +98,9 @@ namespace ams::fs {
bool MountSdCard();
void UnmountSdCard();
bool MountSystem();
void UnmountSystem();
Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path);
Result CreateFile(const char *path, s64 size);

View File

@@ -181,6 +181,112 @@ namespace ams::nxboot {
constinit fs::IStorage *g_boot0_storage = nullptr;
constinit fs::IStorage *g_user_storage = nullptr;
class SystemPartitionStorage : public fs::IStorage {
private:
static constexpr size_t CacheEntries = BITSIZEOF(u32);
static constexpr size_t SectorSize = 0x4000;
private:
fs::SubStorage m_storage;
u8 *m_sector_cache;
u32 *m_sector_ids;
u32 m_sector_flags;
u32 m_next_idx;
private:
Result LoadSector(u8 *sector, u32 sector_id) {
/* Read the sector data. */
R_TRY(m_storage.Read(static_cast<s64>(sector_id) * SectorSize, sector, SectorSize));
/* Decrypt the sector. */
se::DecryptAes128Xts(sector, SectorSize, pkg1::AesKeySlot_BootloaderSystem0, pkg1::AesKeySlot_BootloaderSystem1, sector, SectorSize, sector_id);
/* Mark the sector as freshly loaded. */
m_sector_flags &= ~(1u << (sector_id % CacheEntries));
return ResultSuccess();
}
Result GetSector(u8 **out_sector, u32 sector_id) {
/* Try to find in the cache. */
for (size_t i = 0; i < CacheEntries; ++i) {
if (m_sector_ids[i] == sector_id) {
m_sector_flags &= ~(1u << i);
*out_sector = m_sector_cache + SectorSize * i;
return ResultSuccess();
}
}
/* Find a sector to evict. */
while ((m_sector_flags & (1u << m_next_idx)) == 0) {
m_sector_flags |= (1u << m_next_idx);
m_next_idx = (m_next_idx + 1) % CacheEntries;
}
/* Get the chosen sector. */
*out_sector = m_sector_cache + SectorSize * m_next_idx;
m_next_idx = (m_next_idx + 1) % CacheEntries;
/* Load the sector. */
return this->LoadSector(*out_sector, sector_id);
}
public:
SystemPartitionStorage(s64 ofs, s64 size) : m_storage(*g_user_storage, ofs, size) {
/* Allocate sector cache. */
m_sector_cache = static_cast<u8 *>(AllocateAligned(CacheEntries * SectorSize, SectorSize));
/* Allocate sector ids. */
m_sector_ids = static_cast<u32 *>(AllocateAligned(CacheEntries * sizeof(u32), alignof(u32)));
for (size_t i = 0; i < CacheEntries; ++i) {
m_sector_ids[i] = std::numeric_limits<u32>::max();
}
/* All sectors are dirty. */
m_sector_flags = ~0u;
/* Next sector is 0. */
m_next_idx = 0;
}
virtual Result Read(s64 offset, void *buffer, size_t size) override {
u32 sector_id = offset / SectorSize;
s64 subofs = offset % SectorSize;
u8 *cur_dst = static_cast<u8 *>(buffer);
while (size > 0) {
/* Get the current sector. */
u8 *sector;
R_TRY(this->GetSector(std::addressof(sector), sector_id++));
/* Copy the data. */
const size_t cur_size = std::min<size_t>(SectorSize - subofs, size);
std::memcpy(cur_dst, sector + subofs, cur_size);
/* Advance. */
cur_dst += cur_size;
size -= cur_size;
subofs = 0;
}
return ResultSuccess();
}
virtual Result Flush() override {
return m_storage.Flush();
}
virtual Result GetSize(s64 *out) override {
return m_storage.GetSize(out);
}
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
return fs::ResultUnsupportedOperation();
}
virtual Result SetSize(s64 size) override {
return fs::ResultUnsupportedOperation();
}
};
constinit SystemPartitionStorage *g_system_storage = nullptr;
constinit fs::SubStorage *g_package2_storage = nullptr;
struct Guid {
@@ -227,6 +333,10 @@ namespace ams::nxboot {
};
static_assert(sizeof(Gpt) == 16_KB + 0x200);
constexpr const u16 SystemPartitionName[] = {
'S', 'Y', 'S', 'T', 'E', 'M', 0
};
constexpr const u16 Package2PartitionName[] = {
'B', 'C', 'P', 'K', 'G', '2', '-', '1', '-', 'N', 'o', 'r', 'm', 'a', 'l', '-', 'M', 'a', 'i', 'n', 0
};
@@ -337,15 +447,27 @@ namespace ams::nxboot {
const s64 offset = INT64_C(0x200) * gpt->entries[i].starting_lba;
const u64 size = UINT64_C(0x200) * (gpt->entries[i].ending_lba + 1 - gpt->entries[i].starting_lba);
if (std::memcmp(gpt->entries[i].partition_name, Package2PartitionName, sizeof(Package2PartitionName)) == 0) {
if (std::memcmp(gpt->entries[i].partition_name, SystemPartitionName, sizeof(SystemPartitionName)) == 0) {
g_system_storage = AllocateObject<SystemPartitionStorage>(offset, size);
} else if (std::memcmp(gpt->entries[i].partition_name, Package2PartitionName, sizeof(Package2PartitionName)) == 0) {
g_package2_storage = AllocateObject<fs::SubStorage>(*g_user_storage, offset, size);
}
}
/* Check that we created system storage. */
if (g_system_storage == nullptr) {
ShowFatalError("Failed to initialize SYSTEM\n");
}
/* Check that we created package2 storage. */
if (g_package2_storage == nullptr) {
ShowFatalError("Failed to initialize Package2\n");
}
/* Mount system. */
if (!fs::MountSystem()) {
ShowFatalError("Failed to mount SYSTEM\n");
}
}
Result ReadBoot0(s64 offset, void *dst, size_t size) {
@@ -356,4 +478,8 @@ namespace ams::nxboot {
return g_package2_storage->Read(offset, dst, size);
}
}
Result ReadSystem(s64 offset, void *dst, size_t size) {
return g_system_storage->Read(offset, dst, size);
}
}

View File

@@ -33,11 +33,11 @@ namespace ams::nxboot {
u32 verif_hash;
u32 store_hash;
if (fuse::GetSocType() == fuse::SocType_Erista) {
result = fs::ReadFile(archive_file, AMS_OFFSETOF(ExternalPackage, ovl_mtc_erista), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_erista));
result = fs::ReadFile(archive_file, __builtin_offsetof(ExternalPackage, ovl_mtc_erista), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_erista));
verif_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[-2];
store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(ExternalPackage{}.ovl_mtc_erista) / sizeof(u32)) - 1];
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
result = fs::ReadFile(archive_file, AMS_OFFSETOF(ExternalPackage, ovl_mtc_mariko), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_mariko));
result = fs::ReadFile(archive_file, __builtin_offsetof(ExternalPackage, ovl_mtc_mariko), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_mariko));
verif_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[-1];
store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(ExternalPackage{}.ovl_mtc_mariko) / sizeof(u32)) - 1];
}

View File

@@ -118,12 +118,26 @@ namespace ams::nxboot {
return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_Directory;
}
bool IsFileExist(const char *path) {
[[maybe_unused]] bool IsFileExist(const char *path) {
fs::DirectoryEntryType entry_type;
bool archive;
return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_File;
}
bool IsConcatenationFileExist(const char *path) {
fs::DirectoryEntryType entry_type;
bool archive;
return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && ((entry_type == fs::DirectoryEntryType_File) || (entry_type == fs::DirectoryEntryType_Directory && archive));
}
constinit char g_nca_path[0x40] = "sys:/contents/registered/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.nca";
bool IsNcaExist(const char *nca_name) {
std::memcpy(g_nca_path + 0x19, nca_name, 0x20);
return IsConcatenationFileExist(g_nca_path);
}
bool ConfigureEmummc() {
/* Set magic. */
g_emummc_cfg.base_cfg.magic = secmon::EmummcBaseConfiguration::Magic;
@@ -146,7 +160,7 @@ namespace ams::nxboot {
/* Handle individual fields. */
for (const auto &entry : section.kv_list) {
if (std::strcmp(entry.key, "enabled") == 0) {
enabled = entry.value[0] != '0';
enabled = entry.value[0] == '1';
} else if (std::strcmp(entry.key, "id") == 0) {
id = ParseHexInteger(entry.value);
} else if (std::strcmp(entry.key, "sector") == 0) {
@@ -206,56 +220,143 @@ namespace ams::nxboot {
return package1;
}
ams::TargetFirmware GetApproximateTargetFirmware(const u8 *package1) {
/* Get an approximation of the target firmware. */
ams::TargetFirmware GetTargetFirmware(const u8 *package1) {
/* Get first an approximation of the target firmware. */
ams::TargetFirmware target_firmware = ams::TargetFirmware_Current;
switch (package1[0x1F]) {
case 0x01:
return ams::TargetFirmware_1_0_0;
target_firmware = ams::TargetFirmware_1_0_0;
break;
case 0x02:
return ams::TargetFirmware_2_0_0;
target_firmware = ams::TargetFirmware_2_0_0;
break;
case 0x04:
return ams::TargetFirmware_3_0_0;
target_firmware = ams::TargetFirmware_3_0_0;
break;
case 0x07:
return ams::TargetFirmware_4_0_0;
target_firmware = ams::TargetFirmware_4_0_0;
break;
case 0x0B:
return ams::TargetFirmware_5_0_0;
target_firmware = ams::TargetFirmware_5_0_0;
break;
case 0x0E:
if (std::memcmp(package1 + 0x10, "20180802", 8) == 0) {
return ams::TargetFirmware_6_0_0;
target_firmware = ams::TargetFirmware_6_0_0;
} else if (std::memcmp(package1 + 0x10, "20181107", 8) == 0) {
return ams::TargetFirmware_6_2_0;
target_firmware = ams::TargetFirmware_6_2_0;
} else {
ShowFatalError("Unable to identify package1!\n");
}
break;
case 0x0F:
return ams::TargetFirmware_7_0_0;
target_firmware = ams::TargetFirmware_7_0_0;
break;
case 0x10:
if (std::memcmp(package1 + 0x10, "20190314", 8) == 0) {
return ams::TargetFirmware_8_0_0;
target_firmware = ams::TargetFirmware_8_0_0;
} else if (std::memcmp(package1 + 0x10, "20190531", 8) == 0) {
return ams::TargetFirmware_8_1_0;
target_firmware = ams::TargetFirmware_8_1_0;
} else if (std::memcmp(package1 + 0x10, "20190809", 8) == 0) {
return ams::TargetFirmware_9_0_0;
target_firmware = ams::TargetFirmware_9_0_0;
} else if (std::memcmp(package1 + 0x10, "20191021", 8) == 0) {
return ams::TargetFirmware_9_1_0;
target_firmware = ams::TargetFirmware_9_1_0;
} else if (std::memcmp(package1 + 0x10, "20200303", 8) == 0) {
return ams::TargetFirmware_10_0_0;
target_firmware = ams::TargetFirmware_10_0_0;
} else if (std::memcmp(package1 + 0x10, "20201030", 8) == 0) {
return ams::TargetFirmware_11_0_0;
target_firmware = ams::TargetFirmware_11_0_0;
} else if (std::memcmp(package1 + 0x10, "20210129", 8) == 0) {
return ams::TargetFirmware_12_0_0;
target_firmware = ams::TargetFirmware_12_0_0;
} else if (std::memcmp(package1 + 0x10, "20210422", 8) == 0) {
return ams::TargetFirmware_12_0_2;
target_firmware = ams::TargetFirmware_12_0_2;
} else if (std::memcmp(package1 + 0x10, "20210607", 8) == 0) {
return ams::TargetFirmware_12_1_0;
target_firmware = ams::TargetFirmware_12_1_0;
} else if (std::memcmp(package1 + 0x10, "20210805", 8) == 0) {
return ams::TargetFirmware_13_0_0;
target_firmware = ams::TargetFirmware_13_0_0;
} else {
ShowFatalError("Unable to identify package1!\n");
}
break;
default:
ShowFatalError("Unable to identify package1!\n");
break;
}
ShowFatalError("Unable to identify package1!\n");
#define CHECK_NCA(NCA_ID, VERSION) do { if (IsNcaExist(NCA_ID)) { return ams::TargetFirmware_##VERSION; } } while(0)
if (target_firmware >= ams::TargetFirmware_13_0_0) {
CHECK_NCA("bf2337ee88bd9f963a33b3ecbbc3732a", 13_0_0);
} else if (target_firmware >= ams::TargetFirmware_12_1_0) {
CHECK_NCA("9d9d83d68d9517f245f3e8cd7f93c416", 12_1_0);
} else if (target_firmware >= ams::TargetFirmware_12_0_2) {
CHECK_NCA("a1863a5c0e1cedd442f5e60b0422dc15", 12_0_3);
CHECK_NCA("63d928b5a3016fe8cc0e76d2f06f4e98", 12_0_2);
} else if (target_firmware >= ams::TargetFirmware_12_0_0) {
CHECK_NCA("e65114b456f9d0b566a80e53bade2d89", 12_0_1);
CHECK_NCA("bd4185843550fbba125b20787005d1d2", 12_0_0);
} else if (target_firmware >= ams::TargetFirmware_11_0_0) {
CHECK_NCA("56211c7a5ed20a5332f5cdda67121e37", 11_0_1);
CHECK_NCA("594c90bcdbcccad6b062eadba0cd0e7e", 11_0_0);
} else if (target_firmware >= ams::TargetFirmware_10_0_0) {
CHECK_NCA("26325de4db3909e0ef2379787c7e671d", 10_2_0);
CHECK_NCA("5077973537f6735b564dd7475b779f87", 10_1_1); /* Exclusive to China. */
CHECK_NCA("fd1faed0ca750700d254c0915b93d506", 10_1_0);
CHECK_NCA("34728c771299443420820d8ae490ea41", 10_0_4);
CHECK_NCA("5b1df84f88c3334335bbb45d8522cbb4", 10_0_3);
CHECK_NCA("e951bc9dedcd54f65ffd83d4d050f9e0", 10_0_2);
CHECK_NCA("36ab1acf0c10a2beb9f7d472685f9a89", 10_0_1);
CHECK_NCA("5625cdc21d5f1ca52f6c36ba261505b9", 10_0_0);
} else if (target_firmware >= ams::TargetFirmware_9_1_0) {
CHECK_NCA("09ef4d92bb47b33861e695ba524a2c17", 9_2_0);
CHECK_NCA("c5fbb49f2e3648c8cfca758020c53ecb", 9_1_0);
} else if (target_firmware >= ams::TargetFirmware_9_0_0) {
CHECK_NCA("fd1ffb82dc1da76346343de22edbc97c", 9_0_1);
CHECK_NCA("a6af05b33f8f903aab90c8b0fcbcc6a4", 9_0_0);
} else if (target_firmware >= ams::TargetFirmware_8_1_0) {
CHECK_NCA("724d9b432929ea43e787ad81bf09ae65", 8_1_1); /* 8.1.1-100 from Lite */
CHECK_NCA("e9bb0602e939270a9348bddd9b78827b", 8_1_1); /* 8.1.1-12 from chinese gamecard */
CHECK_NCA("7eedb7006ad855ec567114be601b2a9d", 8_1_0);
} else if (target_firmware >= ams::TargetFirmware_8_0_0) {
CHECK_NCA("6c5426d27c40288302ad616307867eba", 8_0_1);
CHECK_NCA("4fe7b4abcea4a0bcc50975c1a926efcb", 8_0_0);
} else if (target_firmware >= ams::TargetFirmware_7_0_0) {
CHECK_NCA("e6b22c40bb4fa66a151f1dc8db5a7b5c", 7_0_1);
CHECK_NCA("c613bd9660478de69bc8d0e2e7ea9949", 7_0_0);
} else if (target_firmware >= ams::TargetFirmware_6_2_0) {
CHECK_NCA("6dfaaf1a3cebda6307aa770d9303d9b6", 6_2_0);
} else if (target_firmware >= ams::TargetFirmware_6_0_0) {
CHECK_NCA("1d21680af5a034d626693674faf81b02", 6_1_0);
CHECK_NCA("663e74e45ffc86fbbaeb98045feea315", 6_0_1);
CHECK_NCA("258c1786b0f6844250f34d9c6f66095b", 6_0_0); /* Release 6.0.0-5.0 */
CHECK_NCA("286e30bafd7e4197df6551ad802dd815", 6_0_0); /* Pre-Release 6.0.0-4.0 */
} else if (target_firmware >= ams::TargetFirmware_5_0_0) {
CHECK_NCA("fce3b0ea366f9c95fe6498b69274b0e7", 5_1_0);
CHECK_NCA("c5758b0cb8c6512e8967e38842d35016", 5_0_2);
CHECK_NCA("53eb605d4620e8fd50064b24fd57783a", 5_0_1);
CHECK_NCA("09a2f9c16ce1c121ae6d231b35d17515", 5_0_0);
} else if (target_firmware >= ams::TargetFirmware_4_0_0) {
CHECK_NCA("77e1ae7661ad8a718b9b13b70304aeea", 4_1_0);
CHECK_NCA("d0e5d20e3260f3083bcc067483b71274", 4_0_1);
CHECK_NCA("483a24ee3fd7149f9112d1931166a678", 4_0_0);
} else if (target_firmware >= ams::TargetFirmware_3_0_0) {
CHECK_NCA("704129fc89e1fcb85c37b3112e51b0fc", 3_0_2);
CHECK_NCA("1fb00543307337d523ccefa9923e0c50", 3_0_1);
CHECK_NCA("6ebd3447473bade18badbeb5032af87d", 3_0_0);
} else if (target_firmware >= ams::TargetFirmware_2_0_0) {
CHECK_NCA("d1c991c53a8a9038f8c3157a553d876d", 2_3_0);
CHECK_NCA("7f90353dff2d7ce69e19e07ebc0d5489", 2_2_0);
CHECK_NCA("e9b3e75fce00e52fe646156634d229b4", 2_1_0);
CHECK_NCA("7a1f79f8184d4b9bae1755090278f52c", 2_0_0);
} else if (target_firmware >= ams::TargetFirmware_1_0_0) {
CHECK_NCA("a1b287e07f8455e8192f13d0e45a2aaf", 1_0_0); /* 1.0.0 from Factory */
CHECK_NCA("117f7b9c7da3e8cef02340596af206b3", 1_0_0); /* 1.0.0 from Gamecard */
} else {
ShowFatalError("Unable to determine target firmware!\n");
}
#undef CHECK_NCA
/* If we didn't find a more specific firmware, return our package1 approximation. */
return target_firmware;
}
u8 *LoadBootConfigAndPackage2() {
@@ -270,7 +371,7 @@ namespace ams::nxboot {
u8 *package2;
size_t package2_size;
{
constexpr s64 Package2Offset = AMS_OFFSETOF(pkg2::StorageLayout, package2_header);
constexpr s64 Package2Offset = __builtin_offsetof(pkg2::StorageLayout, package2_header);
pkg2::Package2Header header;
if (R_FAILED((result = ReadPackage2(Package2Offset, std::addressof(header), sizeof(header))))) {
@@ -724,7 +825,7 @@ namespace ams::nxboot {
const u8 * const package1 = LoadPackage1(soc_type);
/* Get target firmware. */
const auto target_firmware = GetApproximateTargetFirmware(package1);
const auto target_firmware = GetTargetFirmware(package1);
/* Read/decrypt package2. */
u8 * const package2 = LoadBootConfigAndPackage2();

View File

@@ -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;
}

View File

@@ -22,14 +22,14 @@ namespace ams::nxboot {
class Lz4Uncompressor {
private:
const u8 *m_src;
size_t m_src_size;
size_t m_src_offset;
u8 *m_dst;
size_t m_dst_size;
size_t m_dst_offset;
const u8 *src;
size_t src_size;
size_t src_offset;
u8 *dst;
size_t dst_size;
size_t dst_offset;
public:
Lz4Uncompressor(void *dst, size_t dst_size, const void *src, size_t src_size) : m_src(static_cast<const u8 *>(src)), m_src_size(src_size), m_src_offset(0), m_dst(static_cast<u8 *>(dst)), m_dst_size(dst_size), m_dst_offset(0) {
Lz4Uncompressor(void *dst, size_t dst_size, const void *src, size_t src_size) : src(static_cast<const u8 *>(src)), src_size(src_size), src_offset(0), dst(static_cast<u8 *>(dst)), dst_size(dst_size), dst_offset(0) {
/* ... */
}
@@ -42,7 +42,7 @@ namespace ams::nxboot {
this->Copy(this->GetCopySize(control >> 4));
/* If we've exceeded size, we're done. */
if (m_src_offset >= m_src_size) {
if (this->src_offset >= this->src_size) {
break;
}
@@ -55,21 +55,21 @@ namespace ams::nxboot {
const size_t wide_copy_size = this->GetCopySize(control & 0xF);
/* Copy bytes. */
const size_t end_offset = m_dst_offset + wide_copy_size + 4;
for (size_t cur_offset = m_dst_offset; cur_offset < end_offset; m_dst_offset = (++cur_offset)) {
const size_t end_offset = this->dst_offset + wide_copy_size + 4;
for (size_t cur_offset = this->dst_offset; cur_offset < end_offset; this->dst_offset = (++cur_offset)) {
AMS_ABORT_UNLESS(wide_offset <= cur_offset);
m_dst[cur_offset] = m_dst[cur_offset - wide_offset];
this->dst[cur_offset] = this->dst[cur_offset - wide_offset];
}
}
}
private:
u8 ReadByte() {
return m_src[m_src_offset++];
return this->src[this->src_offset++];
}
bool CanRead() const {
return m_src_offset < m_src_size;
return this->src_offset < this->src_size;
}
size_t GetCopySize(u8 control) {
@@ -87,9 +87,9 @@ namespace ams::nxboot {
}
void Copy(size_t size) {
__builtin_memcpy(m_dst + m_dst_offset, m_src + m_src_offset, size);
m_dst_offset += size;
m_src_offset += size;
__builtin_memcpy(this->dst + this->dst_offset, this->src + this->src_offset, size);
this->dst_offset += size;
this->src_offset += size;
}
};

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = c4d0335b79da7207b49abf1988f45b0168b692f0
parent = 96631d8225611b2b490ec1e8b5a84c1b0e53157a
commit = 0a4c2759a1f73cb5581ed2e87c20e05440a2c037
parent = d14290e3572c52f4dd9ed2a16f698ba12e9eea67
method = merge
cmdver = 0.4.1

View File

@@ -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 +=

View File

@@ -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 +=

View File

@@ -1,5 +0,0 @@
export ATMOSPHERE_DEFINES += -DATMOSPHERE_BOARD_QEMU_VIRT -D__SWITCH__
export ATMOSPHERE_SETTINGS +=
export ATMOSPHERE_CFLAGS +=
export ATMOSPHERE_CXXFLAGS +=
export ATMOSPHERE_ASFLAGS +=

View File

@@ -23,8 +23,7 @@ export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-str
-fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector \
-Wno-format-truncation -Wno-format-zero-length -Wno-stringop-truncation
export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++20 -Wno-invalid-offsetof
export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++20
export ATMOSPHERE_ASFLAGS :=
@@ -39,9 +38,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,30 +48,9 @@ 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
else ifeq ($(ATMOSPHERE_BOARD),qemu-virt)
ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57)
export ATMOSPHERE_ARCH_DIR := arm64
export ATMOSPHERE_BOARD_DIR := qemu/virt
export ATMOSPHERE_OS_DIR := horizon
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
endif
ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57)
@@ -94,27 +69,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 +109,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 +131,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))

View File

@@ -81,9 +81,9 @@ namespace ams::fuse {
DramId_Count,
};
enum RetailInteractiveDisplayState {
RetailInteractiveDisplayState_Disabled = 0,
RetailInteractiveDisplayState_Enabled = 1,
enum QuestState {
QuestState_Disabled = 0,
QuestState_Enabled = 1,
};
void SetRegisterAddress(uintptr_t address);
@@ -102,19 +102,19 @@ namespace ams::fuse {
bool GetSecureBootKey(void *dst);
void GetEcid(br::BootEcid *out);
HardwareType GetHardwareType();
HardwareState GetHardwareState();
u64 GetDeviceId();
PatchVersion GetPatchVersion();
RetailInteractiveDisplayState GetRetailInteractiveDisplayState();
pmic::Regulator GetRegulator();
int GetDeviceUniqueKeyGeneration();
void GetEcid(br::BootEcid *out);
HardwareType GetHardwareType();
HardwareState GetHardwareState();
u64 GetDeviceId();
PatchVersion GetPatchVersion();
QuestState GetQuestState();
pmic::Regulator GetRegulator();
int GetDeviceUniqueKeyGeneration();
SocType GetSocType();
int GetExpectedFuseVersion(TargetFirmware target_fw);
int GetFuseVersion();
bool HasRcmVulnerabilityPatch();
SocType GetSocType();
int GetExpectedFuseVersion(TargetFirmware target_fw);
int GetFuseVersion();
bool HasRcmVulnerabilityPatch();
bool IsOdmProductionMode();
void ConfigureFuseBypass();

View File

@@ -55,9 +55,9 @@ namespace ams::pkg1 {
static_assert(util::is_pod<SecureMonitorParameters>::value);
static_assert(sizeof(SecureMonitorParameters) == 0x200);
static_assert(AMS_OFFSETOF(SecureMonitorParameters, bct_params) == 0x10);
static_assert(AMS_OFFSETOF(SecureMonitorParameters, bootloader_state) == 0xF8);
static_assert(AMS_OFFSETOF(SecureMonitorParameters, secmon_state) == 0xFC);
static_assert(offsetof(SecureMonitorParameters, bct_params) == 0x10);
static_assert(offsetof(SecureMonitorParameters, bootloader_state) == 0xF8);
static_assert(offsetof(SecureMonitorParameters, secmon_state) == 0xFC);
enum BootloaderAttribute {
BootloaderAttribute_None = (0u << 0),

View File

@@ -70,10 +70,6 @@ namespace ams::secmon {
GetConfigurationContext().secmon_cfg.key_generation = generation;
}
ALWAYS_INLINE void SetTargetFirmware(ams::TargetFirmware target_firmware) {
GetConfigurationContext().secmon_cfg.target_firmware = target_firmware;
}
ALWAYS_INLINE pkg1::BootConfig *GetBootConfigStorage() {
return std::addressof(GetConfigurationContext().boot_config);
}

View File

@@ -22,53 +22,52 @@ namespace ams::secmon {
using Address = u64;
struct MemoryRegion {
private:
Address m_start_address;
Address m_end_address;
public:
consteval MemoryRegion(Address address, size_t size) : m_start_address(address), m_end_address(address + size) {
if (m_end_address < m_start_address) {
__builtin_unreachable();
}
}
Address start_address;
Address end_address;
constexpr Address GetStartAddress() const {
return m_start_address;
constexpr MemoryRegion(Address address, size_t size) : start_address(address), end_address(address + size) {
if (end_address < start_address) {
__builtin_unreachable();
}
}
constexpr Address GetAddress() const {
return this->GetStartAddress();
}
constexpr Address GetStartAddress() const {
return this->start_address;
}
constexpr Address GetEndAddress() const {
return m_end_address;
}
constexpr Address GetAddress() const {
return this->GetStartAddress();
}
constexpr Address GetLastAddress() const {
return m_end_address - 1;
}
constexpr Address GetEndAddress() const {
return this->end_address;
}
constexpr size_t GetSize() const {
return m_end_address - m_start_address;
}
constexpr Address GetLastAddress() const {
return this->end_address - 1;
}
constexpr bool Contains(Address address, size_t size) const {
return m_start_address <= address && (address + size - 1) <= this->GetLastAddress();
}
constexpr size_t GetSize() const {
return this->end_address - this->start_address;
}
constexpr bool Contains(const MemoryRegion &rhs) const {
return this->Contains(rhs.GetStartAddress(), rhs.GetSize());
}
constexpr bool Contains(Address address, size_t size) const {
return this->start_address <= address && (address + size - 1) <= this->GetLastAddress();
}
template<typename T = void> requires (std::is_same<T, void>::value || util::is_pod<T>::value)
ALWAYS_INLINE T *GetPointer() const {
return reinterpret_cast<T *>(this->GetAddress());
}
constexpr bool Contains(const MemoryRegion &rhs) const {
return this->Contains(rhs.GetStartAddress(), rhs.GetSize());
}
template<typename T = void> requires (std::is_same<T, void>::value || util::is_pod<T>::value)
ALWAYS_INLINE T *GetEndPointer() const {
return reinterpret_cast<T *>(this->GetEndAddress());
}
template<typename T = void> requires (std::is_same<T, void>::value || util::is_pod<T>::value)
ALWAYS_INLINE T *GetPointer() const {
return reinterpret_cast<T *>(this->GetAddress());
}
template<typename T = void> requires (std::is_same<T, void>::value || util::is_pod<T>::value)
ALWAYS_INLINE T *GetEndPointer() const {
return reinterpret_cast<T *>(this->GetEndAddress());
}
};
constexpr inline const MemoryRegion MemoryRegionVirtual = MemoryRegion(UINT64_C(0x1F0000000), 2_MB);

View File

@@ -128,10 +128,10 @@ namespace ams::secmon {
}
constexpr inline const Address WarmbootStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + AMS_OFFSETOF(VolatileData, warmboot_stack) + sizeof(VolatileData::warmboot_stack);
constexpr inline const Address Core012SmcStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + AMS_OFFSETOF(VolatileData, core012_smc_stack) + sizeof(VolatileData::core012_smc_stack);
constexpr inline const Address WarmbootStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + offsetof(VolatileData, warmboot_stack) + sizeof(VolatileData::warmboot_stack);
constexpr inline const Address Core012SmcStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + offsetof(VolatileData, core012_smc_stack) + sizeof(VolatileData::core012_smc_stack);
constexpr inline const Address Core0ExceptionStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + AMS_OFFSETOF(VolatileData, core_exception_stacks) + CoreExceptionStackSize;
constexpr inline const Address Core0ExceptionStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + offsetof(VolatileData, core_exception_stacks) + CoreExceptionStackSize;
constexpr inline const Address Core1ExceptionStackAddress = Core0ExceptionStackAddress + CoreExceptionStackSize;
constexpr inline const Address Core2ExceptionStackAddress = Core1ExceptionStackAddress + CoreExceptionStackSize;

View File

@@ -37,7 +37,7 @@ namespace ams::crypto::impl {
AMS_UNUSED(key_size, is_encrypt);
/* Set the security engine keyslot. */
m_slot = *static_cast<const int *>(key);
this->slot = *static_cast<const int *>(key);
}
template<size_t KeySize>
@@ -48,14 +48,14 @@ namespace ams::crypto::impl {
if constexpr (KeySize == 16) {
/* Aes 128. */
se::EncryptAes128(dst, dst_size, m_slot, src, src_size);
se::EncryptAes128(dst, dst_size, this->slot, src, src_size);
} else if constexpr (KeySize == 24) {
/* Aes 192. */
/* TODO: se::EncryptAes192(dst, dst_size, m_slot, src, src_size); */
/* TODO: se::EncryptAes192(dst, dst_size, this->slot, src, src_size); */
AMS_UNUSED(dst, dst_size, src, src_size);
} else if constexpr (KeySize == 32) {
/* Aes 256. */
/* TODO: se::EncryptAes256(dst, dst_size, m_slot, src, src_size); */
/* TODO: se::EncryptAes256(dst, dst_size, this->slot, src, src_size); */
AMS_UNUSED(dst, dst_size, src, src_size);
} else {
/* Invalid key size. */
@@ -71,14 +71,14 @@ namespace ams::crypto::impl {
if constexpr (KeySize == 16) {
/* Aes 128. */
se::DecryptAes128(dst, dst_size, m_slot, src, src_size);
se::DecryptAes128(dst, dst_size, this->slot, src, src_size);
} else if constexpr (KeySize == 24) {
/* Aes 192. */
/* TODO: se::DecryptAes192(dst, dst_size, m_slot, src, src_size); */
/* TODO: se::DecryptAes192(dst, dst_size, this->slot, src, src_size); */
AMS_UNUSED(dst, dst_size, src, src_size);
} else if constexpr (KeySize == 32) {
/* Aes 256. */
/* TODO: se::DecryptAes256(dst, dst_size, m_slot, src, src_size); */
/* TODO: se::DecryptAes256(dst, dst_size, this->slot, src, src_size); */
AMS_UNUSED(dst, dst_size, src, src_size);
} else {
/* Invalid key size. */

View File

@@ -37,15 +37,15 @@ namespace ams::fuse {
};
struct OdmWord4 {
using HardwareState1 = util::BitPack32::Field<0, 2, int>;
using HardwareType1 = util::BitPack32::Field<HardwareState1::Next, 1, int>;
using DramId = util::BitPack32::Field<HardwareType1::Next, 5, int>;
using HardwareType2 = util::BitPack32::Field<DramId::Next, 1, int>;
using HardwareState2 = util::BitPack32::Field<HardwareType2::Next, 1, int>;
using RetailInteractiveDisplayState = util::BitPack32::Field<HardwareState2::Next, 1, int>;
using FormatVersion = util::BitPack32::Field<RetailInteractiveDisplayState::Next, 1, int>;
using Reserved = util::BitPack32::Field<FormatVersion::Next, 4, int>;
using HardwareType3 = util::BitPack32::Field<Reserved::Next, 4, int>;
using HardwareState1 = util::BitPack32::Field<0, 2, int>;
using HardwareType1 = util::BitPack32::Field<HardwareState1::Next, 1, int>;
using DramId = util::BitPack32::Field<HardwareType1::Next, 5, int>;
using HardwareType2 = util::BitPack32::Field<DramId::Next, 1, int>;
using HardwareState2 = util::BitPack32::Field<HardwareType2::Next, 1, int>;
using QuestState = util::BitPack32::Field<HardwareState2::Next, 1, int>;
using FormatVersion = util::BitPack32::Field<QuestState::Next, 1, int>;
using Reserved = util::BitPack32::Field<FormatVersion::Next, 4, int>;
using HardwareType3 = util::BitPack32::Field<Reserved::Next, 4, int>;
};
struct OdmWord28 {
@@ -343,8 +343,8 @@ namespace ams::fuse {
return static_cast<PatchVersion>(static_cast<int>(GetSocType() << 12) | patch_version);
}
RetailInteractiveDisplayState GetRetailInteractiveDisplayState() {
return static_cast<RetailInteractiveDisplayState>(util::BitPack32{GetCommonOdmWord(4)}.Get<OdmWord4::RetailInteractiveDisplayState>());
QuestState GetQuestState() {
return static_cast<QuestState>(util::BitPack32{GetCommonOdmWord(4)}.Get<OdmWord4::QuestState>());
}
pmic::Regulator GetRegulator() {

View File

@@ -191,27 +191,27 @@ namespace ams::gic {
}
void SetPriority(int interrupt_id, int priority) {
ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, ipriorityr), BITSIZEOF(u8), interrupt_id, priority);
ReadWrite(g_distributor_address + offsetof(GicDistributor, ipriorityr), BITSIZEOF(u8), interrupt_id, priority);
}
void SetInterruptGroup(int interrupt_id, int group) {
ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, igroupr), 1, interrupt_id, group);
ReadWrite(g_distributor_address + offsetof(GicDistributor, igroupr), 1, interrupt_id, group);
}
void SetEnable(int interrupt_id, bool enable) {
Write(g_distributor_address + AMS_OFFSETOF(GicDistributor, isenabler), 1, interrupt_id, enable);
Write(g_distributor_address + offsetof(GicDistributor, isenabler), 1, interrupt_id, enable);
}
void SetSpiTargetCpu(int interrupt_id, u32 cpu_mask) {
ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, itargetsr), BITSIZEOF(u8), interrupt_id, cpu_mask);
ReadWrite(g_distributor_address + offsetof(GicDistributor, itargetsr), BITSIZEOF(u8), interrupt_id, cpu_mask);
}
void SetSpiMode(int interrupt_id, InterruptMode mode) {
ReadWrite(g_distributor_address + AMS_OFFSETOF(GicDistributor, icfgr), 2, interrupt_id, static_cast<u32>(mode) << 1);
ReadWrite(g_distributor_address + offsetof(GicDistributor, icfgr), 2, interrupt_id, static_cast<u32>(mode) << 1);
}
void SetPending(int interrupt_id) {
Write(g_distributor_address + AMS_OFFSETOF(GicDistributor, ispendr), 1, interrupt_id, 1);
Write(g_distributor_address + offsetof(GicDistributor, ispendr), 1, interrupt_id, 1);
}
int GetInterruptRequestId() {

View File

@@ -104,18 +104,6 @@ $(eval $(call ATMOSPHERE_ADD_TARGET, audit, $(TARGET)_audit.a, \
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_release, $(TARGET)_qemu_virt.a, \
ATMOSPHERE_BUILD_SETTINGS="" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_debug, $(TARGET)_qemu_virt_debug.a, \
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_DEBUGGING" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, qemu_virt_audit, $(TARGET)_qemu_virt_audit.a, \
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \
))
#---------------------------------------------------------------------------------
-include $(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME).mk
@@ -154,6 +142,8 @@ $(OFILES_SRC) : $(HFILES_BIN)
kern_libc_generic.o: CFLAGS += -fno-builtin
kern_k_auto_object.o kern_k_debug_base_process_holder.o: CXXFLAGS += -fno-lto
#---------------------------------------------------------------------------------
%_bin.h %.bin.o : %.bin
#---------------------------------------------------------------------------------

View File

@@ -90,7 +90,3 @@
/* Main functionality. */
#include <mesosphere/kern_main.hpp>
/* Deferred includes. */
#include <mesosphere/kern_k_auto_object_impls.hpp>
#include <mesosphere/kern_k_scheduler_impls.hpp>

View File

@@ -248,9 +248,8 @@ namespace ams::kern::arch::arm {
return id;
}
private:
static constexpr size_t PriorityShift = BITSIZEOF(u8) - util::CountTrailingZeros(NumPriorityLevels);
static constexpr size_t PriorityShift = BITSIZEOF(u8) - __builtin_ctz(NumPriorityLevels);
static_assert(PriorityShift < BITSIZEOF(u8));
static_assert(util::IsPowerOfTwo(NumPriorityLevels));
static constexpr ALWAYS_INLINE u8 ToGicPriorityValue(s32 level) {
return (level << PriorityShift) | ((1 << PriorityShift) - 1);

View File

@@ -35,17 +35,17 @@ namespace ams::kern::init {
static_assert(alignof(KInitArguments) == util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE));
static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)));
static_assert(AMS_OFFSETOF(KInitArguments, ttbr0) == INIT_ARGUMENTS_TTBR0);
static_assert(AMS_OFFSETOF(KInitArguments, ttbr1) == INIT_ARGUMENTS_TTBR1);
static_assert(AMS_OFFSETOF(KInitArguments, tcr) == INIT_ARGUMENTS_TCR);
static_assert(AMS_OFFSETOF(KInitArguments, mair) == INIT_ARGUMENTS_MAIR);
static_assert(AMS_OFFSETOF(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR);
static_assert(AMS_OFFSETOF(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR);
static_assert(AMS_OFFSETOF(KInitArguments, sctlr) == INIT_ARGUMENTS_SCTLR);
static_assert(AMS_OFFSETOF(KInitArguments, sp) == INIT_ARGUMENTS_SP);
static_assert(AMS_OFFSETOF(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
static_assert(AMS_OFFSETOF(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
static_assert(AMS_OFFSETOF(KInitArguments, setup_function) == INIT_ARGUMENTS_SETUP_FUNCTION);
static_assert(AMS_OFFSETOF(KInitArguments, exception_stack) == INIT_ARGUMENTS_EXCEPTION_STACK);
static_assert(__builtin_offsetof(KInitArguments, ttbr0) == INIT_ARGUMENTS_TTBR0);
static_assert(__builtin_offsetof(KInitArguments, ttbr1) == INIT_ARGUMENTS_TTBR1);
static_assert(__builtin_offsetof(KInitArguments, tcr) == INIT_ARGUMENTS_TCR);
static_assert(__builtin_offsetof(KInitArguments, mair) == INIT_ARGUMENTS_MAIR);
static_assert(__builtin_offsetof(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR);
static_assert(__builtin_offsetof(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR);
static_assert(__builtin_offsetof(KInitArguments, sctlr) == INIT_ARGUMENTS_SCTLR);
static_assert(__builtin_offsetof(KInitArguments, sp) == INIT_ARGUMENTS_SP);
static_assert(__builtin_offsetof(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
static_assert(__builtin_offsetof(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
static_assert(__builtin_offsetof(KInitArguments, setup_function) == INIT_ARGUMENTS_SETUP_FUNCTION);
static_assert(__builtin_offsetof(KInitArguments, exception_stack) == INIT_ARGUMENTS_EXCEPTION_STACK);
}

View File

@@ -34,22 +34,19 @@ namespace ams::kern::arch::arm64::init {
}
}
/* NOTE: Nintendo uses virtual functions, rather than a concept + template. */
template<typename T>
concept IsInitialPageAllocator = requires (T &t, KPhysicalAddress phys_addr, size_t size) {
{ t.Allocate(size) } -> std::same_as<KPhysicalAddress>;
{ t.Free(phys_addr, size) } -> std::same_as<void>;
};
template<IsInitialPageAllocator _PageAllocator>
class KInitialPageTableTemplate {
class KInitialPageTable {
public:
using PageAllocator = _PageAllocator;
class IPageAllocator {
public:
virtual KPhysicalAddress Allocate(size_t size) = 0;
virtual void Free(KPhysicalAddress phys_addr, size_t size) = 0;
};
private:
KPhysicalAddress m_l1_tables[2];
u32 m_num_entries[2];
public:
KInitialPageTableTemplate(KVirtualAddress start_address, KVirtualAddress end_address, PageAllocator &allocator) {
KInitialPageTable(KVirtualAddress start_address, KVirtualAddress end_address, IPageAllocator &allocator) {
/* Set tables. */
m_l1_tables[0] = AllocateNewPageTable(allocator);
m_l1_tables[1] = AllocateNewPageTable(allocator);
@@ -59,7 +56,7 @@ namespace ams::kern::arch::arm64::init {
m_num_entries[1] = ((end_address / L1BlockSize) & (MaxPageTableEntries - 1)) - ((start_address / L1BlockSize) & (MaxPageTableEntries - 1)) + 1;
}
KInitialPageTableTemplate() {
KInitialPageTable() {
/* Set tables. */
m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize);
m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize);
@@ -98,7 +95,7 @@ namespace ams::kern::arch::arm64::init {
return l3_table + ((GetInteger(address) / L3BlockSize) & (MaxPageTableEntries - 1));
}
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(PageAllocator &allocator) {
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(IPageAllocator &allocator) {
auto address = allocator.Allocate(PageSize);
ClearNewPageTable(address);
return address;
@@ -279,7 +276,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));
@@ -326,7 +323,7 @@ namespace ams::kern::arch::arm64::init {
}
}
public:
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, PageAllocator &allocator) {
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, IPageAllocator &allocator) {
/* Ensure that addresses and sizes are page aligned. */
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize));
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize));
@@ -350,6 +347,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 +358,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 +381,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 +392,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;
}
@@ -701,9 +700,10 @@ namespace ams::kern::arch::arm64::init {
this->PhysicallyRandomize(virt_addr, size, L3BlockSize, do_copy);
cpu::StoreEntireCacheForInit();
}
};
class KInitialPageAllocator final {
class KInitialPageAllocator final : public KInitialPageTable::IPageAllocator {
private:
static constexpr inline size_t FreeUnitSize = BITSIZEOF(u64) * PageSize;
struct FreeListEntry {
@@ -807,11 +807,11 @@ namespace ams::kern::arch::arm64::init {
}
}
KPhysicalAddress Allocate(size_t size) {
virtual KPhysicalAddress Allocate(size_t size) override {
return this->Allocate(size, size);
}
void Free(KPhysicalAddress phys_addr, size_t size) {
virtual void Free(KPhysicalAddress phys_addr, size_t size) override {
auto **prev_next = std::addressof(m_state.free_head);
auto *new_chunk = reinterpret_cast<FreeListEntry *>(GetInteger(phys_addr));
if (auto *cur = m_state.free_head; cur != nullptr) {
@@ -863,8 +863,5 @@ namespace ams::kern::arch::arm64::init {
*prev_next = new_chunk;
}
};
static_assert(IsInitialPageAllocator<KInitialPageAllocator>);
using KInitialPageTable = KInitialPageTableTemplate<KInitialPageAllocator>;
}

View File

@@ -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

View File

@@ -30,8 +30,6 @@ namespace ams::kern::arch::arm64::cpu {
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
constexpr inline size_t NumCores = 4;
#elif defined(ATMOSPHERE_BOARD_QEMU_VIRT)
constexpr inline size_t NumCores = 4;
#else
#error "Unknown Board for cpu::NumCores"
#endif
@@ -52,19 +50,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 +171,7 @@ namespace ams::kern::arch::arm64::cpu {
NOINLINE void SynchronizeAllCores();
/* Cache management helpers. */
void ClearPageToZeroImpl(void *);
void StoreEntireCacheForInit();
void FlushEntireCacheForInit();
@@ -194,16 +184,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 +207,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();

View File

@@ -34,9 +34,8 @@ namespace ams::kern::arch::arm64 {
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
public:
/* NOTE: These are virtual in Nintendo's kernel. */
Result GetThreadContextImpl(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags);
Result SetThreadContextImpl(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags);
virtual Result GetThreadContextImpl(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags) override;
virtual Result SetThreadContextImpl(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags) override;
private:
Result GetFpuContext(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags);
Result SetFpuContext(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags);

View File

@@ -45,40 +45,40 @@ namespace ams::kern::arch::arm64 {
};
static_assert(sizeof(KExceptionContext) == EXCEPTION_CONTEXT_SIZE);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 0]) == EXCEPTION_CONTEXT_X0);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 1]) == EXCEPTION_CONTEXT_X1);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 2]) == EXCEPTION_CONTEXT_X2);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 3]) == EXCEPTION_CONTEXT_X3);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 4]) == EXCEPTION_CONTEXT_X4);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 5]) == EXCEPTION_CONTEXT_X5);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 6]) == EXCEPTION_CONTEXT_X6);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 7]) == EXCEPTION_CONTEXT_X7);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 8]) == EXCEPTION_CONTEXT_X8);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 9]) == EXCEPTION_CONTEXT_X9);
static_assert(AMS_OFFSETOF(KExceptionContext, x[10]) == EXCEPTION_CONTEXT_X10);
static_assert(AMS_OFFSETOF(KExceptionContext, x[11]) == EXCEPTION_CONTEXT_X11);
static_assert(AMS_OFFSETOF(KExceptionContext, x[12]) == EXCEPTION_CONTEXT_X12);
static_assert(AMS_OFFSETOF(KExceptionContext, x[13]) == EXCEPTION_CONTEXT_X13);
static_assert(AMS_OFFSETOF(KExceptionContext, x[14]) == EXCEPTION_CONTEXT_X14);
static_assert(AMS_OFFSETOF(KExceptionContext, x[15]) == EXCEPTION_CONTEXT_X15);
static_assert(AMS_OFFSETOF(KExceptionContext, x[16]) == EXCEPTION_CONTEXT_X16);
static_assert(AMS_OFFSETOF(KExceptionContext, x[17]) == EXCEPTION_CONTEXT_X17);
static_assert(AMS_OFFSETOF(KExceptionContext, x[18]) == EXCEPTION_CONTEXT_X18);
static_assert(AMS_OFFSETOF(KExceptionContext, x[19]) == EXCEPTION_CONTEXT_X19);
static_assert(AMS_OFFSETOF(KExceptionContext, x[20]) == EXCEPTION_CONTEXT_X20);
static_assert(AMS_OFFSETOF(KExceptionContext, x[21]) == EXCEPTION_CONTEXT_X21);
static_assert(AMS_OFFSETOF(KExceptionContext, x[22]) == EXCEPTION_CONTEXT_X22);
static_assert(AMS_OFFSETOF(KExceptionContext, x[23]) == EXCEPTION_CONTEXT_X23);
static_assert(AMS_OFFSETOF(KExceptionContext, x[24]) == EXCEPTION_CONTEXT_X24);
static_assert(AMS_OFFSETOF(KExceptionContext, x[25]) == EXCEPTION_CONTEXT_X25);
static_assert(AMS_OFFSETOF(KExceptionContext, x[26]) == EXCEPTION_CONTEXT_X26);
static_assert(AMS_OFFSETOF(KExceptionContext, x[27]) == EXCEPTION_CONTEXT_X27);
static_assert(AMS_OFFSETOF(KExceptionContext, x[28]) == EXCEPTION_CONTEXT_X28);
static_assert(AMS_OFFSETOF(KExceptionContext, x[29]) == EXCEPTION_CONTEXT_X29);
static_assert(AMS_OFFSETOF(KExceptionContext, x[30]) == EXCEPTION_CONTEXT_X30);
static_assert(AMS_OFFSETOF(KExceptionContext, sp) == EXCEPTION_CONTEXT_SP);
static_assert(AMS_OFFSETOF(KExceptionContext, pc) == EXCEPTION_CONTEXT_PC);
static_assert(AMS_OFFSETOF(KExceptionContext, psr) == EXCEPTION_CONTEXT_PSR);
static_assert(AMS_OFFSETOF(KExceptionContext, tpidr) == EXCEPTION_CONTEXT_TPIDR);
static_assert(__builtin_offsetof(KExceptionContext, x[ 0]) == EXCEPTION_CONTEXT_X0);
static_assert(__builtin_offsetof(KExceptionContext, x[ 1]) == EXCEPTION_CONTEXT_X1);
static_assert(__builtin_offsetof(KExceptionContext, x[ 2]) == EXCEPTION_CONTEXT_X2);
static_assert(__builtin_offsetof(KExceptionContext, x[ 3]) == EXCEPTION_CONTEXT_X3);
static_assert(__builtin_offsetof(KExceptionContext, x[ 4]) == EXCEPTION_CONTEXT_X4);
static_assert(__builtin_offsetof(KExceptionContext, x[ 5]) == EXCEPTION_CONTEXT_X5);
static_assert(__builtin_offsetof(KExceptionContext, x[ 6]) == EXCEPTION_CONTEXT_X6);
static_assert(__builtin_offsetof(KExceptionContext, x[ 7]) == EXCEPTION_CONTEXT_X7);
static_assert(__builtin_offsetof(KExceptionContext, x[ 8]) == EXCEPTION_CONTEXT_X8);
static_assert(__builtin_offsetof(KExceptionContext, x[ 9]) == EXCEPTION_CONTEXT_X9);
static_assert(__builtin_offsetof(KExceptionContext, x[10]) == EXCEPTION_CONTEXT_X10);
static_assert(__builtin_offsetof(KExceptionContext, x[11]) == EXCEPTION_CONTEXT_X11);
static_assert(__builtin_offsetof(KExceptionContext, x[12]) == EXCEPTION_CONTEXT_X12);
static_assert(__builtin_offsetof(KExceptionContext, x[13]) == EXCEPTION_CONTEXT_X13);
static_assert(__builtin_offsetof(KExceptionContext, x[14]) == EXCEPTION_CONTEXT_X14);
static_assert(__builtin_offsetof(KExceptionContext, x[15]) == EXCEPTION_CONTEXT_X15);
static_assert(__builtin_offsetof(KExceptionContext, x[16]) == EXCEPTION_CONTEXT_X16);
static_assert(__builtin_offsetof(KExceptionContext, x[17]) == EXCEPTION_CONTEXT_X17);
static_assert(__builtin_offsetof(KExceptionContext, x[18]) == EXCEPTION_CONTEXT_X18);
static_assert(__builtin_offsetof(KExceptionContext, x[19]) == EXCEPTION_CONTEXT_X19);
static_assert(__builtin_offsetof(KExceptionContext, x[20]) == EXCEPTION_CONTEXT_X20);
static_assert(__builtin_offsetof(KExceptionContext, x[21]) == EXCEPTION_CONTEXT_X21);
static_assert(__builtin_offsetof(KExceptionContext, x[22]) == EXCEPTION_CONTEXT_X22);
static_assert(__builtin_offsetof(KExceptionContext, x[23]) == EXCEPTION_CONTEXT_X23);
static_assert(__builtin_offsetof(KExceptionContext, x[24]) == EXCEPTION_CONTEXT_X24);
static_assert(__builtin_offsetof(KExceptionContext, x[25]) == EXCEPTION_CONTEXT_X25);
static_assert(__builtin_offsetof(KExceptionContext, x[26]) == EXCEPTION_CONTEXT_X26);
static_assert(__builtin_offsetof(KExceptionContext, x[27]) == EXCEPTION_CONTEXT_X27);
static_assert(__builtin_offsetof(KExceptionContext, x[28]) == EXCEPTION_CONTEXT_X28);
static_assert(__builtin_offsetof(KExceptionContext, x[29]) == EXCEPTION_CONTEXT_X29);
static_assert(__builtin_offsetof(KExceptionContext, x[30]) == EXCEPTION_CONTEXT_X30);
static_assert(__builtin_offsetof(KExceptionContext, sp) == EXCEPTION_CONTEXT_SP);
static_assert(__builtin_offsetof(KExceptionContext, pc) == EXCEPTION_CONTEXT_PC);
static_assert(__builtin_offsetof(KExceptionContext, psr) == EXCEPTION_CONTEXT_PSR);
static_assert(__builtin_offsetof(KExceptionContext, tpidr) == EXCEPTION_CONTEXT_TPIDR);
}

View File

@@ -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;
}
};

View File

@@ -36,10 +36,6 @@ namespace ams::kern::arch::arm64 {
KInterruptName_SecurePhysicalTimer = 29,
KInterruptName_NonSecurePhysicalTimer = 30,
KInterruptName_LegacyNIrq = 31,
#elif defined(ATMOSPHERE_BOARD_QEMU_VIRT)
KInterruptName_VirtualTimer = 27,
KInterruptName_SecurePhysicalTimer = 29,
KInterruptName_NonSecurePhysicalTimer = 30,
#endif
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)

View File

@@ -168,8 +168,7 @@ namespace ams::kern::arch::arm64 {
return entry;
}
public:
constexpr explicit KPageTable(util::ConstantInitializeTag) : KPageTableBase(util::ConstantInitialize), m_manager(), m_ttbr(), m_asid() { /* ... */ }
explicit KPageTable() { /* ... */ }
constexpr KPageTable() : KPageTableBase(), m_manager(), m_ttbr(), m_asid() { /* ... */ }
static NOINLINE void Initialize(s32 core_id);
@@ -219,27 +218,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 +248,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();

View File

@@ -42,7 +42,7 @@ namespace ams::kern::arch::arm64 {
const L3PageTableEntry *l3_entry;
};
private:
static constexpr size_t PageBits = util::CountTrailingZeros(PageSize);
static constexpr size_t PageBits = __builtin_ctzll(PageSize);
static constexpr size_t NumLevels = 3;
static constexpr size_t LevelBits = 9;
static_assert(NumLevels > 0);
@@ -105,9 +105,7 @@ namespace ams::kern::arch::arm64 {
return GetL3EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address);
}
public:
constexpr explicit KPageTableImpl(util::ConstantInitializeTag) : m_table(), m_is_kernel(), m_num_entries() { /* ... */ }
explicit KPageTableImpl() { /* ... */ }
constexpr KPageTableImpl() : m_table(), m_is_kernel(), m_num_entries() { /* ... */ }
NOINLINE void InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end);
NOINLINE void InitializeForProcess(void *tb, KVirtualAddress start, KVirtualAddress end);

View File

@@ -23,6 +23,8 @@ namespace ams::kern::arch::arm64 {
private:
KPageTable m_page_table;
public:
constexpr KProcessPageTable() : m_page_table() { /* ... */ }
void Activate(u64 id) {
/* Activate the page table with the specified contextidr. */
m_page_table.Activate(id);

View File

@@ -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;

View File

@@ -25,7 +25,7 @@ namespace ams::kern::arch::arm64 {
KPageTable m_page_table;
u64 m_ttbr0_identity[cpu::NumCores];
public:
constexpr KSupervisorPageTable() : m_page_table(util::ConstantInitialize), m_ttbr0_identity() { /* ... */ }
constexpr KSupervisorPageTable() : m_page_table(), m_ttbr0_identity() { /* ... */ }
NOINLINE void Initialize(s32 core_id);

View File

@@ -57,8 +57,7 @@ namespace ams::kern::arch::arm64 {
static void RestoreFpuRegisters64(const KThreadContext &);
static void RestoreFpuRegisters32(const KThreadContext &);
public:
constexpr explicit KThreadContext(util::ConstantInitializeTag) : m_callee_saved(), m_lr(), m_sp(), m_cpacr(), m_fpcr(), m_fpsr(), m_fpu_registers(), m_locked() { /* ... */ }
explicit KThreadContext() { /* ... */ }
constexpr explicit KThreadContext() : m_callee_saved(), m_lr(), m_sp(), m_cpacr(), m_fpcr(), m_fpsr(), m_fpu_registers(), m_locked() { /* ... */ }
Result Initialize(KVirtualAddress u_pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, bool is_user, bool is_64_bit, bool is_main);
Result Finalize();
@@ -87,25 +86,25 @@ namespace ams::kern::arch::arm64 {
consteval bool KThreadContext::ValidateOffsets() {
static_assert(sizeof(KThreadContext) == THREAD_CONTEXT_SIZE);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.registers) == THREAD_CONTEXT_CPU_REGISTERS);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x19) == THREAD_CONTEXT_X19);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x20) == THREAD_CONTEXT_X20);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x21) == THREAD_CONTEXT_X21);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x22) == THREAD_CONTEXT_X22);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x23) == THREAD_CONTEXT_X23);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x24) == THREAD_CONTEXT_X24);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x25) == THREAD_CONTEXT_X25);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x26) == THREAD_CONTEXT_X26);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x27) == THREAD_CONTEXT_X27);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x28) == THREAD_CONTEXT_X28);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x29) == THREAD_CONTEXT_X29);
static_assert(AMS_OFFSETOF(KThreadContext, m_lr) == THREAD_CONTEXT_LR);
static_assert(AMS_OFFSETOF(KThreadContext, m_sp) == THREAD_CONTEXT_SP);
static_assert(AMS_OFFSETOF(KThreadContext, m_cpacr) == THREAD_CONTEXT_CPACR);
static_assert(AMS_OFFSETOF(KThreadContext, m_fpcr) == THREAD_CONTEXT_FPCR);
static_assert(AMS_OFFSETOF(KThreadContext, m_fpsr) == THREAD_CONTEXT_FPSR);
static_assert(AMS_OFFSETOF(KThreadContext, m_fpu_registers) == THREAD_CONTEXT_FPU_REGISTERS);
static_assert(AMS_OFFSETOF(KThreadContext, m_locked) == THREAD_CONTEXT_LOCKED);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.registers) == THREAD_CONTEXT_CPU_REGISTERS);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x19) == THREAD_CONTEXT_X19);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x20) == THREAD_CONTEXT_X20);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x21) == THREAD_CONTEXT_X21);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x22) == THREAD_CONTEXT_X22);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x23) == THREAD_CONTEXT_X23);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x24) == THREAD_CONTEXT_X24);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x25) == THREAD_CONTEXT_X25);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x26) == THREAD_CONTEXT_X26);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x27) == THREAD_CONTEXT_X27);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x28) == THREAD_CONTEXT_X28);
static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x29) == THREAD_CONTEXT_X29);
static_assert(__builtin_offsetof(KThreadContext, m_lr) == THREAD_CONTEXT_LR);
static_assert(__builtin_offsetof(KThreadContext, m_sp) == THREAD_CONTEXT_SP);
static_assert(__builtin_offsetof(KThreadContext, m_cpacr) == THREAD_CONTEXT_CPACR);
static_assert(__builtin_offsetof(KThreadContext, m_fpcr) == THREAD_CONTEXT_FPCR);
static_assert(__builtin_offsetof(KThreadContext, m_fpsr) == THREAD_CONTEXT_FPSR);
static_assert(__builtin_offsetof(KThreadContext, m_fpu_registers) == THREAD_CONTEXT_FPU_REGISTERS);
static_assert(__builtin_offsetof(KThreadContext, m_locked) == THREAD_CONTEXT_LOCKED);
return true;
}

View File

@@ -1,95 +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_select_cpu.hpp>
#include <mesosphere/kern_select_interrupt_manager.hpp>
namespace ams::kern::arch::arm64::smc {
template<int SmcId, bool DisableInterrupt>
void SecureMonitorCall(u64 *buf) {
/* Load arguments into registers. */
register u64 x0 asm("x0") = buf[0];
register u64 x1 asm("x1") = buf[1];
register u64 x2 asm("x2") = buf[2];
register u64 x3 asm("x3") = buf[3];
register u64 x4 asm("x4") = buf[4];
register u64 x5 asm("x5") = buf[5];
register u64 x6 asm("x6") = buf[6];
register u64 x7 asm("x7") = buf[7];
/* Perform the call. */
if constexpr (DisableInterrupt) {
KScopedInterruptDisable di;
/* Backup the current thread pointer. */
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
__asm__ __volatile__("smc %c[smc_id]"
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
: [smc_id]"i"(SmcId)
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
);
/* Restore the current thread pointer into X18. */
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
} else {
/* Backup the current thread pointer. */
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
__asm__ __volatile__("smc %c[smc_id]"
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
: [smc_id]"i"(SmcId)
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
);
/* Restore the current thread pointer into X18. */
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
}
/* Store arguments to output. */
buf[0] = x0;
buf[1] = x1;
buf[2] = x2;
buf[3] = x3;
buf[4] = x4;
buf[5] = x5;
buf[6] = x6;
buf[7] = x7;
}
enum PsciFunction {
PsciFunction_CpuSuspend = 0xC4000001,
PsciFunction_CpuOff = 0x84000002,
PsciFunction_CpuOn = 0xC4000003,
};
template<int SmcId, bool DisableInterrupt>
u64 PsciCall(PsciFunction function, u64 x1 = 0, u64 x2 = 0, u64 x3 = 0, u64 x4 = 0, u64 x5 = 0, u64 x6 = 0, u64 x7 = 0) {
ams::svc::lp64::SecureMonitorArguments args = { { function, x1, x2, x3, x4, x5, x6, x7 } };
SecureMonitorCall<SmcId, DisableInterrupt>(args.r);
return args.r[0];
}
template<int SmcId, bool DisableInterrupt>
u64 CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
return PsciCall<SmcId, DisableInterrupt>(PsciFunction_CpuOn, core_id, entrypoint, arg);
}
}

View File

@@ -44,13 +44,13 @@ namespace ams::kern::board::generic {
return ams::kern::svc::ResultNotImplemented();
}
Result ALWAYS_INLINE Map(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool is_aligned) {
MESOSPHERE_UNUSED(page_table, process_address, size, device_address, device_perm, is_aligned);
Result ALWAYS_INLINE Map(size_t *out_mapped_size, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings) {
MESOSPHERE_UNUSED(out_mapped_size, pg, device_address, device_perm, refresh_mappings);
return ams::kern::svc::ResultNotImplemented();
}
Result ALWAYS_INLINE Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) {
MESOSPHERE_UNUSED(page_table, process_address, size, device_address);
Result ALWAYS_INLINE Unmap(const KPageGroup &pg, KDeviceVirtualAddress device_address) {
MESOSPHERE_UNUSED(pg, device_address);
return ams::kern::svc::ResultNotImplemented();
}

View File

@@ -61,12 +61,7 @@ namespace ams::kern::board::nintendo::nx {
return KPageTable::GetPageTablePhysicalAddress(addr);
}
public:
constexpr KDevicePageTable()
: m_tables{Null<KVirtualAddress>, Null<KVirtualAddress>, Null<KVirtualAddress>, Null<KVirtualAddress>},
m_table_asids(), m_attached_device(), m_attached_value(), m_detached_value(), m_hs_attached_value(), m_hs_detached_value()
{
/* ... */
}
constexpr KDevicePageTable() : m_tables(), m_table_asids(), m_attached_device(), m_attached_value(), m_detached_value(), m_hs_attached_value(), m_hs_detached_value() { /* ... */ }
Result Initialize(u64 space_address, u64 space_size);
void Finalize();

View File

@@ -15,12 +15,9 @@
*/
#pragma once
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
namespace ams::kern {
constexpr inline KPhysicalAddress MainMemoryAddress = 0x80000000;
constexpr inline size_t MainMemorySize = 4_GB;
constexpr inline size_t MainMemorySizeMax = 8_GB;

View File

@@ -15,17 +15,23 @@
*/
#pragma once
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_system_control_base.hpp>
namespace ams::kern {
struct InitialProcessBinaryLayout;
}
namespace ams::kern::board::nintendo::nx {
class KSystemControl : public KSystemControlBase {
class KSystemControl {
public:
class Init : public KSystemControlBase::Init {
class Init {
public:
/* Initialization. */
static size_t GetRealMemorySize();
static size_t GetIntendedMemorySize();
static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address);
static void GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out);
static bool ShouldIncreaseThreadResourceLimit();
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
static size_t GetApplicationPoolSize();
@@ -34,7 +40,7 @@ namespace ams::kern::board::nintendo::nx {
static u8 GetDebugLogUartPort();
/* Randomness. */
static void GenerateRandom(u64 *dst, size_t count);
static void GenerateRandomBytes(void *dst, size_t size);
static u64 GenerateRandomRange(u64 min, u64 max);
};
public:
@@ -44,7 +50,7 @@ namespace ams::kern::board::nintendo::nx {
static NOINLINE u32 GetCreateProcessMemoryPool();
/* Randomness. */
static void GenerateRandom(u64 *dst, size_t count);
static void GenerateRandomBytes(void *dst, size_t size);
static u64 GenerateRandomRange(u64 min, u64 max);
static u64 GenerateRandomU64();
@@ -52,12 +58,23 @@ namespace ams::kern::board::nintendo::nx {
static void ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value);
static Result ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value);
static ALWAYS_INLINE u32 ReadRegisterPrivileged(ams::svc::PhysicalAddress address) {
u32 v;
ReadWriteRegisterPrivileged(std::addressof(v), address, 0x00000000u, 0);
return v;
}
static ALWAYS_INLINE void WriteRegisterPrivileged(ams::svc::PhysicalAddress address, u32 value) {
u32 v;
ReadWriteRegisterPrivileged(std::addressof(v), address, 0xFFFFFFFFu, value);
}
/* Power management. */
static void SleepSystem();
static NORETURN void StopSystem(void *arg = nullptr);
/* User access. */
static void CallSecureMonitorFromUserImpl(ams::svc::lp64::SecureMonitorArguments *args);
static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);
/* Secure Memory. */
static size_t CalculateRequiredSecureMemorySize(size_t size, u32 pool);

View File

@@ -1,33 +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>
namespace ams::kern::board::qemu::virt::impl::cpu {
/* Virtual to Physical core map. */
constexpr inline const s32 VirtualToPhysicalCoreMap[BITSIZEOF(u64)] = {
0, 1, 2, 3, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 3,
};
}

View File

@@ -1,27 +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_typed_address.hpp>
namespace ams::kern {
constexpr inline KPhysicalAddress MainMemoryAddress = 0x40000000;
constexpr inline size_t MainMemorySize = 4_GB;
constexpr inline size_t MainMemorySizeMax = 8_GB;
}

View File

@@ -1,20 +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/>.
*/
/* All architectures must define NumBoardDeviceRegions. */
constexpr inline const auto NumBoardDeviceRegions = 0;
/* UNUSED: .Derive(NumBoardDeviceRegions, 0); */

View File

@@ -1,28 +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_system_control_base.hpp>
namespace ams::kern::board::qemu::virt {
class KSystemControl : public KSystemControlBase {
public:
/* User access. */
static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);
};
}

View File

@@ -54,63 +54,63 @@ namespace ams::kern::init::Elf::Elf64 {
class Dyn {
private:
SXword m_tag;
SXword tag;
union {
Xword m_value;
Addr m_ptr;
Xword value;
Addr ptr;
};
public:
constexpr ALWAYS_INLINE SXword GetTag() const {
return m_tag;
return this->tag;
}
constexpr ALWAYS_INLINE Xword GetValue() const {
return m_value;
return this->value;
}
constexpr ALWAYS_INLINE Addr GetPtr() const {
return m_ptr;
return this->ptr;
}
};
class Rel {
private:
Addr m_offset;
Xword m_info;
Addr offset;
Xword info;
public:
constexpr ALWAYS_INLINE Addr GetOffset() const {
return m_offset;
return this->offset;
}
constexpr ALWAYS_INLINE Xword GetSym() const {
return m_info >> 32;
return this->info >> 32;
}
constexpr ALWAYS_INLINE Xword GetType() const {
return m_info & 0xFFFFFFFF;
return this->info & 0xFFFFFFFF;
}
};
class Rela {
private:
Addr m_offset;
Xword m_info;
SXword m_addend;
Addr offset;
Xword info;
SXword addend;
public:
constexpr ALWAYS_INLINE Addr GetOffset() const {
return m_offset;
return this->offset;
}
constexpr ALWAYS_INLINE Xword GetSym() const {
return m_info >> 32;
return this->info >> 32;
}
constexpr ALWAYS_INLINE Xword GetType() const {
return m_info & 0xFFFFFFFF;
return this->info & 0xFFFFFFFF;
}
constexpr ALWAYS_INLINE SXword GetAddend() const {
return m_addend;
return this->addend;
}
};

View File

@@ -32,25 +32,3 @@
//#define MESOSPHERE_BUILD_FOR_TRACING
#define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP
#define MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP
/* NOTE: This enables fast class token storage using a class member. */
/* This saves a virtual call when doing KAutoObject->DynCast<>(), */
/* at the cost of storing class tokens inside the class object. */
/* However, as of (10/16/2021) KAutoObject has an unused class member */
/* 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. */
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
//#define MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES
#else
#define MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES
#endif

View File

@@ -43,8 +43,6 @@ namespace ams::kern {
#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
#define MESOSPHERE_DEBUG_LOG_USE_UART
#elif defined(ATMOSPHERE_BOARD_QEMU_VIRT)
#define MESOSPHERE_DEBUG_LOG_USE_SEMIHOSTING
#else
#error "Unknown board for Default Debug Log Source"
#endif

View File

@@ -25,7 +25,7 @@ namespace ams::kern {
private:
ThreadTree m_tree;
public:
constexpr KAddressArbiter() = default;
constexpr KAddressArbiter() : m_tree() { /* ... */ }
Result SignalToAddress(uintptr_t addr, ams::svc::SignalType type, s32 value, s32 count) {
switch (type) {

View File

@@ -22,73 +22,27 @@ namespace ams::kern {
class KProcess;
#if defined(MESOSPHERE_BUILD_FOR_DEBUGGING) || defined(MESOSPHERE_BUILD_FOR_AUDITING)
#define MESOSPHERE_AUTO_OBJECT_TYPENAME_IMPL(CLASS) #CLASS
#else
#define MESOSPHERE_AUTO_OBJECT_TYPENAME_IMPL(CLASS) ""
#endif
#define MESOSPHERE_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
NON_COPYABLE(CLASS); \
NON_MOVEABLE(CLASS); \
private: \
friend class ::ams::kern::KClassTokenGenerator; \
static constexpr inline auto ObjectType = ::ams::kern::KClassTokenGenerator::ObjectType::CLASS; \
static constexpr inline const char * const TypeName = MESOSPHERE_AUTO_OBJECT_TYPENAME_IMPL(CLASS); \
static constexpr inline const char * const TypeName = #CLASS; \
static constexpr inline ClassTokenType ClassToken() { return ::ams::kern::ClassToken<CLASS>; } \
public: \
using BaseClass = BASE_CLASS; \
static consteval ALWAYS_INLINE TypeObj GetStaticTypeObj() { \
static constexpr ALWAYS_INLINE TypeObj GetStaticTypeObj() { \
constexpr ClassTokenType Token = ClassToken(); \
return TypeObj(TypeName, Token); \
} \
static consteval ALWAYS_INLINE const char *GetStaticTypeName() { return TypeName; } \
static constexpr ALWAYS_INLINE const char *GetStaticTypeName() { return TypeName; } \
virtual TypeObj GetTypeObj() const { return GetStaticTypeObj(); } \
virtual const char *GetTypeName() { return GetStaticTypeName(); } \
private:
class KAutoObject {
public:
class ReferenceCount {
NON_COPYABLE(ReferenceCount);
NON_MOVEABLE(ReferenceCount);
private:
using Storage = u32;
private:
util::Atomic<Storage> m_value;
public:
ALWAYS_INLINE explicit ReferenceCount() { /* ... */ }
constexpr ALWAYS_INLINE explicit ReferenceCount(Storage v) : m_value(v) { /* ... */ }
ALWAYS_INLINE void operator=(Storage v) { m_value = v; }
ALWAYS_INLINE Storage GetValue() const { return m_value.Load(); }
ALWAYS_INLINE bool Open() {
/* Atomically increment the reference count, only if it's positive. */
u32 cur = m_value.Load<std::memory_order_relaxed>();
do {
if (AMS_UNLIKELY(cur == 0)) {
MESOSPHERE_AUDIT(cur != 0);
return false;
}
MESOSPHERE_ABORT_UNLESS(cur < cur + 1);
} while (AMS_UNLIKELY(!m_value.CompareExchangeWeak<std::memory_order_relaxed>(cur, cur + 1)));
return true;
}
ALWAYS_INLINE bool Close() {
/* Atomically decrement the reference count, not allowing it to become negative. */
u32 cur = m_value.Load<std::memory_order_relaxed>();
do {
MESOSPHERE_ABORT_UNLESS(cur > 0);
} while (AMS_UNLIKELY(!m_value.CompareExchangeWeak<std::memory_order_relaxed>(cur, cur - 1)));
/* Return whether the object was closed. */
return cur - 1 == 0;
}
};
protected:
class TypeObj {
private:
@@ -109,61 +63,37 @@ namespace ams::kern {
}
constexpr ALWAYS_INLINE bool IsDerivedFrom(const TypeObj &rhs) {
return IsClassTokenDerivedFrom(this->GetClassToken(), rhs.GetClassToken());
}
static constexpr ALWAYS_INLINE bool IsClassTokenDerivedFrom(ClassTokenType derived, ClassTokenType base) {
return (derived | base) == derived;
return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken();
}
};
private:
MESOSPHERE_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
private:
KAutoObject *m_next_closed_object;
ReferenceCount m_ref_count;
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
ClassTokenType m_class_token;
#endif
std::atomic<u32> m_ref_count;
public:
constexpr ALWAYS_INLINE explicit KAutoObject(util::ConstantInitializeTag) : m_next_closed_object(nullptr), m_ref_count(0)
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
, m_class_token(0)
#endif
{
MESOSPHERE_ASSERT_THIS();
}
ALWAYS_INLINE explicit KAutoObject() : m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
static KAutoObject *Create(KAutoObject *ptr);
public:
constexpr ALWAYS_INLINE explicit KAutoObject() : m_next_closed_object(nullptr), m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
/* Destroy is responsible for destroying the auto object's resources when ref_count hits zero. */
virtual void Destroy() { MESOSPHERE_ASSERT_THIS(); }
/* Finalize is responsible for cleaning up resource, but does not destroy the object. */
/* NOTE: This is a virtual function in official kernel, but because everything which uses it */
/* is already using CRTP for slab heap, we have devirtualized it for performance gain. */
/* virtual void Finalize() { MESOSPHERE_ASSERT_THIS(); } */
virtual void Finalize() { MESOSPHERE_ASSERT_THIS(); }
/* NOTE: This is a virtual function which is unused-except-for-debug in Nintendo's kernel. */
/* virtual KProcess *GetOwner() const { return nullptr; } */
virtual KProcess *GetOwner() const { return nullptr; }
u32 GetReferenceCount() const {
return m_ref_count.GetValue();
return m_ref_count.load();
}
ALWAYS_INLINE bool IsDerivedFrom(const TypeObj &rhs) const {
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.GetClassToken());
#else
return this->GetTypeObj().IsDerivedFrom(rhs);
#endif
return this->GetTypeObj().IsDerivedFrom(rhs);
}
ALWAYS_INLINE bool IsDerivedFrom(const KAutoObject &rhs) const {
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.m_class_token);
#else
return this->IsDerivedFrom(rhs.GetTypeObj());
#endif
return this->IsDerivedFrom(rhs.GetTypeObj());
}
template<typename Derived>
@@ -190,19 +120,8 @@ namespace ams::kern {
}
}
NOINLINE bool Open() {
MESOSPHERE_ASSERT_THIS();
return m_ref_count.Open();
}
NOINLINE void Close() {
MESOSPHERE_ASSERT_THIS();
if (m_ref_count.Close()) {
this->ScheduleDestruction();
}
}
bool Open();
void Close();
private:
/* NOTE: This has to be defined *after* KThread is defined. */
/* Nintendo seems to handle this by defining Open/Close() in a cpp, but we'd like them to remain in headers. */
@@ -211,46 +130,34 @@ namespace ams::kern {
public:
/* Getter, for KThread. */
ALWAYS_INLINE KAutoObject *GetNextClosedObject() { return m_next_closed_object; }
public:
template<typename Derived> requires (std::derived_from<Derived, KAutoObject>)
static ALWAYS_INLINE void Create(typename std::type_identity<Derived>::type *obj) {
/* Get auto object pointer. */
KAutoObject &auto_object = *static_cast<KAutoObject *>(obj);
/* If we should, set our class token. */
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
{
constexpr auto Token = Derived::GetStaticTypeObj().GetClassToken();
auto_object.m_class_token = Token;
}
#endif
/* Initialize reference count to 1. */
auto_object.m_ref_count = 1;
}
};
class KAutoObjectWithListBase : public KAutoObject {
private:
void *m_alignment_forcer_unused[0];
public:
constexpr ALWAYS_INLINE explicit KAutoObjectWithListBase(util::ConstantInitializeTag) : KAutoObject(util::ConstantInitialize), m_alignment_forcer_unused{} { /* ... */ }
class KAutoObjectWithListContainer;
ALWAYS_INLINE explicit KAutoObjectWithListBase() { /* ... */ }
};
class KAutoObjectWithList : public KAutoObjectWithListBase {
class KAutoObjectWithList : public KAutoObject {
private:
template<typename>
friend class KAutoObjectWithListContainer;
private:
util::IntrusiveRedBlackTreeNode m_list_node;
public:
constexpr ALWAYS_INLINE KAutoObjectWithList(util::ConstantInitializeTag) : KAutoObjectWithListBase(util::ConstantInitialize), m_list_node(util::ConstantInitialize) { /* ... */ }
ALWAYS_INLINE explicit KAutoObjectWithList() { /* ... */ }
constexpr ALWAYS_INLINE KAutoObjectWithList() : m_list_node() { /* ... */ }
static ALWAYS_INLINE int Compare(const KAutoObjectWithList &lhs, const KAutoObjectWithList &rhs) {
const u64 lid = lhs.GetId();
const u64 rid = rhs.GetId();
if (lid < rid) {
return -1;
} else if (lid > rid) {
return 1;
} else {
return 0;
}
}
public:
/* NOTE: This is virtual in Nintendo's kernel. */
u64 GetId() const;
virtual u64 GetId() const {
return reinterpret_cast<u64>(this);
}
};
template<typename T> requires std::derived_from<T, KAutoObject>
@@ -266,6 +173,7 @@ namespace ams::kern {
std::swap(m_obj, rhs.m_obj);
}
public:
constexpr ALWAYS_INLINE KScopedAutoObject() : m_obj(nullptr) { /* ... */ }
constexpr ALWAYS_INLINE KScopedAutoObject(T *o) : m_obj(o) {
if (m_obj != nullptr) {
m_obj->Open();
@@ -320,52 +228,5 @@ namespace ams::kern {
constexpr ALWAYS_INLINE bool IsNotNull() const { return m_obj != nullptr; }
};
template<typename T> requires std::derived_from<T, KAutoObject>
class KSharedAutoObject {
private:
T *m_object;
KAutoObject::ReferenceCount m_ref_count;
public:
explicit KSharedAutoObject() : m_object(nullptr) { /* ... */ }
void Attach(T *obj) {
MESOSPHERE_ASSERT(m_object == nullptr);
/* Set our object. */
m_object = obj;
/* Open reference to our object. */
m_object->Open();
/* Set our reference count. */
m_ref_count = 1;
}
bool Open() {
return m_ref_count.Open();
}
void Close() {
if (m_ref_count.Close()) {
this->Detach();
}
}
ALWAYS_INLINE T *Get() const {
return m_object;
}
private:
void Detach() {
/* Close our object, if we have one. */
if (T * const object = m_object; AMS_LIKELY(object != nullptr)) {
/* Set our object to a debug sentinel value, which will cause crash if accessed. */
m_object = reinterpret_cast<T *>(1);
/* Close reference to our object. */
object->Close();
}
}
};
}

View File

@@ -20,131 +20,45 @@
namespace ams::kern {
namespace impl {
class KAutoObjectWithListContainer {
NON_COPYABLE(KAutoObjectWithListContainer);
NON_MOVEABLE(KAutoObjectWithListContainer);
public:
using ListType = util::IntrusiveRedBlackTreeMemberTraits<&KAutoObjectWithList::m_list_node>::TreeType<KAutoObjectWithList>;
public:
class ListAccessor : public KScopedLightLock {
private:
ListType &m_list;
public:
explicit ListAccessor(KAutoObjectWithListContainer *container) : KScopedLightLock(container->m_lock), m_list(container->m_object_list) { /* ... */ }
explicit ListAccessor(KAutoObjectWithListContainer &container) : KScopedLightLock(container.m_lock), m_list(container.m_object_list) { /* ... */ }
template<typename T>
struct GetAutoObjectWithListComparator;
class KAutoObjectWithListContainerBase {
NON_COPYABLE(KAutoObjectWithListContainerBase);
NON_MOVEABLE(KAutoObjectWithListContainerBase);
protected:
template<typename ListType>
class ListAccessorImpl {
NON_COPYABLE(ListAccessorImpl);
NON_MOVEABLE(ListAccessorImpl);
private:
KScopedLightLock m_lk;
ListType &m_list;
public:
explicit ALWAYS_INLINE ListAccessorImpl(KAutoObjectWithListContainerBase *container, ListType &list) : m_lk(container->m_lock), m_list(list) { /* ... */ }
explicit ALWAYS_INLINE ListAccessorImpl(KAutoObjectWithListContainerBase &container, ListType &list) : m_lk(container.m_lock), m_list(list) { /* ... */ }
ALWAYS_INLINE ~ListAccessorImpl() { /* ... */ }
ALWAYS_INLINE typename ListType::iterator begin() const {
return m_list.begin();
}
ALWAYS_INLINE typename ListType::iterator end() const {
return m_list.end();
}
ALWAYS_INLINE typename ListType::iterator find(typename ListType::const_reference ref) const {
return m_list.find(ref);
}
ALWAYS_INLINE typename ListType::iterator find_key(typename ListType::const_key_reference ref) const {
return m_list.find_key(ref);
}
};
template<typename ListType>
friend class ListAccessorImpl;
private:
KLightLock m_lock;
protected:
constexpr KAutoObjectWithListContainerBase() : m_lock() { /* ... */ }
ALWAYS_INLINE void InitializeImpl() { MESOSPHERE_ASSERT_THIS(); }
ALWAYS_INLINE void FinalizeImpl() { MESOSPHERE_ASSERT_THIS(); }
template<typename ListType>
void RegisterImpl(KAutoObjectWithList *obj, ListType &list) {
MESOSPHERE_ASSERT_THIS();
KScopedLightLock lk(m_lock);
list.insert(*obj);
}
template<typename ListType>
void UnregisterImpl(KAutoObjectWithList *obj, ListType &list) {
MESOSPHERE_ASSERT_THIS();
KScopedLightLock lk(m_lock);
list.erase(list.iterator_to(*obj));
}
template<typename U, typename ListType>
size_t GetOwnedCountImpl(const KProcess *owner, ListType &list) {
MESOSPHERE_ASSERT_THIS();
KScopedLightLock lk(m_lock);
size_t count = 0;
for (const auto &obj : list) {
MESOSPHERE_AUDIT(obj.DynamicCast<const U *>() != nullptr);
if (static_cast<const U &>(obj).GetOwner() == owner) {
++count;
}
typename ListType::iterator begin() const {
return m_list.begin();
}
return count;
}
};
typename ListType::iterator end() const {
return m_list.end();
}
struct DummyKAutoObjectWithListComparator {
static NOINLINE int Compare(KAutoObjectWithList &lhs, KAutoObjectWithList &rhs) {
MESOSPHERE_UNUSED(lhs, rhs);
MESOSPHERE_PANIC("DummyKAutoObjectWithListComparator invoked");
}
};
typename ListType::iterator find(typename ListType::const_reference ref) const {
return m_list.find(ref);
}
};
}
template<typename T>
class KAutoObjectWithListContainer : public impl::KAutoObjectWithListContainerBase {
private:
using Base = impl::KAutoObjectWithListContainerBase;
public:
class ListAccessor;
friend class ListAccessor;
template<typename Comparator>
using ListType = util::IntrusiveRedBlackTreeMemberTraits<&KAutoObjectWithList::m_list_node>::TreeType<Comparator>;
using DummyListType = ListType<impl::DummyKAutoObjectWithListComparator>;
private:
DummyListType m_dummy_object_list;
KLightLock m_lock;
ListType m_object_list;
public:
constexpr ALWAYS_INLINE KAutoObjectWithListContainer() : Base(), m_dummy_object_list() { static_assert(std::derived_from<T, KAutoObjectWithList>); }
constexpr KAutoObjectWithListContainer() : m_lock(), m_object_list() { MESOSPHERE_ASSERT_THIS(); }
ALWAYS_INLINE void Initialize() { return this->InitializeImpl(); }
ALWAYS_INLINE void Finalize() { return this->FinalizeImpl(); }
void Initialize() { MESOSPHERE_ASSERT_THIS(); }
void Finalize() { MESOSPHERE_ASSERT_THIS(); }
void Register(T *obj);
void Unregister(T *obj);
private:
size_t GetOwnedCountChecked(const KProcess *owner);
public:
template<typename U> requires (std::same_as<U, T> && requires (const U &u) { { u.GetOwner() } -> std::convertible_to<const KProcess *>; })
ALWAYS_INLINE size_t GetOwnedCount(const KProcess *owner) {
return this->GetOwnedCountChecked(owner);
}
void Register(KAutoObjectWithList *obj);
void Unregister(KAutoObjectWithList *obj);
size_t GetOwnedCount(KProcess *owner);
};

View File

@@ -1,163 +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_class_token.hpp>
namespace ams::kern {
/* NOTE: This header is included after all other KAutoObjects. */
namespace impl {
template<typename T> requires std::derived_from<T, KAutoObject>
consteval bool IsAutoObjectInheritanceValidImpl() {
#define CLASS_TOKEN_HANDLER(CLASSNAME) \
if constexpr (std::same_as<T, CLASSNAME>) { \
if (T::GetStaticTypeObj().GetClassToken() != ::ams::kern::ClassToken<CLASSNAME>) { \
return false; \
} \
} else { \
if (T::GetStaticTypeObj().IsDerivedFrom(CLASSNAME::GetStaticTypeObj()) != std::derived_from<T, CLASSNAME>) { \
return false; \
} \
}
FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER)
#undef CLASS_TOKEN_HANDLER
return true;
}
consteval bool IsEveryAutoObjectInheritanceValid() {
#define CLASS_TOKEN_HANDLER(CLASSNAME) if (!IsAutoObjectInheritanceValidImpl<CLASSNAME>()) { return false; }
FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER)
#undef CLASS_TOKEN_HANDLER
return true;
}
static_assert(IsEveryAutoObjectInheritanceValid());
template<typename T>
concept IsAutoObjectWithSpecializedGetId = std::derived_from<T, KAutoObjectWithList> && requires (const T &t, const KAutoObjectWithList &l) {
{ t.GetIdImpl() } -> std::same_as<decltype(l.GetId())>;
};
template<typename T>
struct AutoObjectWithListComparatorImpl {
using RedBlackKeyType = u64;
static ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; }
static ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KAutoObjectWithList &v) {
if constexpr (IsAutoObjectWithSpecializedGetId<T>) {
return static_cast<const T &>(v).GetIdImpl();
} else {
return reinterpret_cast<u64>(std::addressof(v));
}
}
template<typename U> requires (std::same_as<U, KAutoObjectWithList> || std::same_as<U, RedBlackKeyType>)
static ALWAYS_INLINE int Compare(const U &lhs, const KAutoObjectWithList &rhs) {
const u64 lid = GetRedBlackKey(lhs);
const u64 rid = GetRedBlackKey(rhs);
if (lid < rid) {
return -1;
} else if (lid > rid) {
return 1;
} else {
return 0;
}
}
};
template<typename T>
using AutoObjectWithListComparator = AutoObjectWithListComparatorImpl<typename std::conditional<IsAutoObjectWithSpecializedGetId<T>, T, KAutoObjectWithList>::type>;
template<typename T>
using TrueObjectContainerListType = typename KAutoObjectWithListContainer<T>::ListType<AutoObjectWithListComparator<T>>;
template<typename T>
ALWAYS_INLINE TrueObjectContainerListType<T> &GetTrueObjectContainerList(typename KAutoObjectWithListContainer<T>::DummyListType &l) {
static_assert(alignof(l) == alignof(impl::TrueObjectContainerListType<T>));
static_assert(sizeof(l) == sizeof(impl::TrueObjectContainerListType<T>));
return *reinterpret_cast<TrueObjectContainerListType<T> *>(std::addressof(l));
}
}
ALWAYS_INLINE void KAutoObject::ScheduleDestruction() {
MESOSPHERE_ASSERT_THIS();
/* Set our object to destroy. */
m_next_closed_object = GetCurrentThread().GetClosedObject();
/* Set ourselves as the thread's next object to destroy. */
GetCurrentThread().SetClosedObject(this);
}
template<typename T>
class KAutoObjectWithListContainer<T>::ListAccessor : public impl::KAutoObjectWithListContainerBase::ListAccessorImpl<impl::TrueObjectContainerListType<T>> {
NON_COPYABLE(ListAccessor);
NON_MOVEABLE(ListAccessor);
private:
using BaseListAccessor = impl::KAutoObjectWithListContainerBase::ListAccessorImpl<impl::TrueObjectContainerListType<T>>;
public:
explicit ALWAYS_INLINE ListAccessor(KAutoObjectWithListContainer *container) : BaseListAccessor(container, impl::GetTrueObjectContainerList<T>(container->m_dummy_object_list)) { /* ... */ }
explicit ALWAYS_INLINE ListAccessor(KAutoObjectWithListContainer &container) : BaseListAccessor(container, impl::GetTrueObjectContainerList<T>(container.m_dummy_object_list)) { /* ... */ }
ALWAYS_INLINE ~ListAccessor() { /* ... */ }
};
template<typename T>
ALWAYS_INLINE void KAutoObjectWithListContainer<T>::Register(T *obj) {
return this->RegisterImpl(obj, impl::GetTrueObjectContainerList<T>(m_dummy_object_list));
}
template<typename T>
ALWAYS_INLINE void KAutoObjectWithListContainer<T>::Unregister(T *obj) {
return this->UnregisterImpl(obj, impl::GetTrueObjectContainerList<T>(m_dummy_object_list));
}
template<typename T>
ALWAYS_INLINE size_t KAutoObjectWithListContainer<T>::GetOwnedCountChecked(const KProcess *owner) {
return this->GetOwnedCountImpl<T>(owner, impl::GetTrueObjectContainerList<T>(m_dummy_object_list));
}
inline u64 KAutoObjectWithList::GetId() const {
#define CLASS_TOKEN_HANDLER(CLASSNAME) \
if constexpr (impl::IsAutoObjectWithSpecializedGetId<CLASSNAME>) { \
if (const CLASSNAME * const derived = this->DynamicCast<const CLASSNAME *>(); derived != nullptr) { \
return []<typename T>(const T * const t_derived) ALWAYS_INLINE_LAMBDA -> u64 { \
static_assert(std::same_as<T, CLASSNAME>); \
if constexpr (impl::IsAutoObjectWithSpecializedGetId<CLASSNAME>) { \
return impl::AutoObjectWithListComparator<CLASSNAME>::GetRedBlackKey(*t_derived); \
} else { \
AMS_ASSUME(false); \
} \
}(derived); \
} \
}
FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER)
#undef CLASS_TOKEN_HANDLER
return impl::AutoObjectWithListComparator<KAutoObjectWithList>::GetRedBlackKey(*this);
}
}

View File

@@ -55,16 +55,48 @@ namespace ams::kern {
return static_cast<u32>(type) + 1;
}
static constexpr u32 CountTrailingZero(u32 flag) {
for (u32 i = 0; i < BITSIZEOF(u32); i++) {
if (flag & (1u << i)) {
return i;
}
}
return BITSIZEOF(u32);
}
static constexpr u32 GetCapabilityId(CapabilityType type) {
const u32 flag = GetCapabilityFlag(type);
if (std::is_constant_evaluated()) {
return CountTrailingZero(flag);
} else {
return static_cast<u32>(__builtin_ctz(flag));
}
}
template<size_t Index, size_t Count, typename T = u32>
using Field = util::BitPack32::Field<Index, Count, T>;
#define DEFINE_FIELD(name, prev, ...) using name = Field<prev::Next, __VA_ARGS__>
template<CapabilityType Type>
static constexpr inline u32 CapabilityFlag = static_cast<u32>(Type) + 1;
static constexpr inline u32 CapabilityFlag = []() -> u32 {
return static_cast<u32>(Type) + 1;
}();
template<CapabilityType Type>
static constexpr inline u32 CapabilityId = util::CountTrailingZeros<u32>(CapabilityFlag<Type>);
static constexpr inline u32 CapabilityId = []() -> u32 {
const u32 flag = static_cast<u32>(Type) + 1;
if (std::is_constant_evaluated()) {
for (u32 i = 0; i < BITSIZEOF(u32); i++) {
if (flag & (1u << i)) {
return i;
}
}
return BITSIZEOF(u32);
} else {
return __builtin_ctz(flag);
}
}();
struct CorePriority {
using IdBits = Field<0, CapabilityId<CapabilityType::CorePriority> + 1>;
@@ -82,11 +114,7 @@ namespace ams::kern {
DEFINE_FIELD(Index, Mask, 3);
};
#if defined(MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES)
static constexpr u64 PhysicalMapAllowedMask = (1ul << 40) - 1;
#else
static constexpr u64 PhysicalMapAllowedMask = (1ul << 36) - 1;
#endif
struct MapRange {
using IdBits = Field<0, CapabilityId<CapabilityType::MapRange> + 1>;
@@ -98,15 +126,9 @@ namespace ams::kern {
struct MapRangeSize {
using IdBits = Field<0, CapabilityId<CapabilityType::MapRange> + 1>;
DEFINE_FIELD(Pages, IdBits, 20);
#if defined(MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES)
DEFINE_FIELD(AddressHigh, Pages, 4);
DEFINE_FIELD(Normal, AddressHigh, 1, bool);
#else
DEFINE_FIELD(Pages, IdBits, 20);
DEFINE_FIELD(Reserved, Pages, 4);
DEFINE_FIELD(Normal, Reserved, 1, bool);
#endif
};
struct MapIoPage {
@@ -181,14 +203,14 @@ namespace ams::kern {
CapabilityFlag<CapabilityType::HandleTable> |
CapabilityFlag<CapabilityType::DebugFlags>;
private:
svc::SvcAccessFlagSet m_svc_access_flags;
InterruptFlagSet m_irq_access_flags;
u64 m_core_mask;
u64 m_priority_mask;
util::BitPack32 m_debug_capabilities;
s32 m_handle_table_size;
util::BitPack32 m_intended_kernel_version;
u32 m_program_type;
svc::SvcAccessFlagSet m_svc_access_flags{};
InterruptFlagSet m_irq_access_flags{};
u64 m_core_mask{};
u64 m_priority_mask{};
util::BitPack32 m_debug_capabilities{0};
s32 m_handle_table_size{};
util::BitPack32 m_intended_kernel_version{0};
u32 m_program_type{};
private:
constexpr bool SetSvcAllowed(u32 id) {
if (AMS_LIKELY(id < m_svc_access_flags.GetCount())) {
@@ -223,8 +245,7 @@ namespace ams::kern {
Result SetCapabilities(const u32 *caps, s32 num_caps, KProcessPageTable *page_table);
Result SetCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table);
public:
constexpr explicit KCapabilities(util::ConstantInitializeTag) : m_svc_access_flags{}, m_irq_access_flags{}, m_core_mask{}, m_priority_mask{}, m_debug_capabilities{0}, m_handle_table_size{}, m_intended_kernel_version{}, m_program_type{} { /* ... */ }
KCapabilities() { /* ... */ }
constexpr KCapabilities() = default;
Result Initialize(const u32 *caps, s32 num_caps, KProcessPageTable *page_table);
Result Initialize(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table);

View File

@@ -21,35 +21,6 @@ namespace ams::kern {
class KAutoObject;
#define FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(HANDLER) \
HANDLER(KAutoObject) \
\
HANDLER(KSynchronizationObject) \
HANDLER(KReadableEvent) \
\
HANDLER(KInterruptEvent) \
HANDLER(KDebug) \
HANDLER(KThread) \
HANDLER(KServerPort) \
HANDLER(KServerSession) \
HANDLER(KClientPort) \
HANDLER(KClientSession) \
HANDLER(KProcess) \
HANDLER(KResourceLimit) \
HANDLER(KLightSession) \
HANDLER(KPort) \
HANDLER(KSession) \
HANDLER(KSharedMemory) \
HANDLER(KEvent) \
HANDLER(KLightClientSession) \
HANDLER(KLightServerSession) \
HANDLER(KTransferMemory) \
HANDLER(KDeviceAddressSpace) \
HANDLER(KSessionRequest) \
HANDLER(KCodeMemory) \
HANDLER(KIoPool) \
HANDLER(KIoRegion)
class KClassTokenGenerator {
public:
using TokenBaseType = u16;
@@ -142,11 +113,8 @@ namespace ams::kern {
KIoPool,
KIoRegion,
FinalClassesLast,
FinalClassesEnd = FinalClassesStart + NumFinalClasses,
};
static_assert(ObjectType::FinalClassesLast <= ObjectType::FinalClassesEnd);
template<typename T>
static constexpr inline TokenBaseType ClassToken = GetClassToken<T>();
@@ -157,37 +125,4 @@ namespace ams::kern {
template<typename T>
static constexpr inline ClassTokenType ClassToken = KClassTokenGenerator::ClassToken<T>;
namespace impl {
consteval bool IsKClassTokenGeneratorForEachMacroValid() {
auto IsObjectTypeIncludedByMacro = [](KClassTokenGenerator::ObjectType object_type) -> bool {
#define CLASS_TOKEN_HANDLER(CLASSNAME) if (object_type == KClassTokenGenerator::ObjectType::CLASSNAME) { return true; }
FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER)
#undef CLASS_TOKEN_HANDLER
return false;
};
if (!IsObjectTypeIncludedByMacro(KClassTokenGenerator::ObjectType::KAutoObject)) {
return false;
}
for (auto base = util::ToUnderlying(KClassTokenGenerator::ObjectType::BaseClassesStart); base < util::ToUnderlying(KClassTokenGenerator::ObjectType::BaseClassesEnd); ++base) {
if (!IsObjectTypeIncludedByMacro(static_cast<KClassTokenGenerator::ObjectType>(base))) {
return false;
}
}
for (auto fin = util::ToUnderlying(KClassTokenGenerator::ObjectType::FinalClassesStart); fin < util::ToUnderlying(KClassTokenGenerator::ObjectType::FinalClassesLast); ++fin) {
if (!IsObjectTypeIncludedByMacro(static_cast<KClassTokenGenerator::ObjectType>(fin))) {
return false;
}
}
return true;
}
static_assert(IsKClassTokenGeneratorForEachMacroValid());
}
}

View File

@@ -28,14 +28,12 @@ namespace ams::kern {
class KClientPort final : public KSynchronizationObject {
MESOSPHERE_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
private:
util::Atomic<s32> m_num_sessions;
util::Atomic<s32> m_peak_sessions;
std::atomic<s32> m_num_sessions;
std::atomic<s32> m_peak_sessions;
s32 m_max_sessions;
KPort *m_parent;
public:
constexpr explicit KClientPort(util::ConstantInitializeTag) : KSynchronizationObject(util::ConstantInitialize), m_num_sessions(0), m_peak_sessions(0), m_max_sessions(), m_parent() { /* ... */ }
explicit KClientPort() { /* ... */ }
constexpr KClientPort() : m_num_sessions(), m_peak_sessions(), m_max_sessions(), m_parent() { /* ... */ }
void Initialize(KPort *parent, s32 max_sessions);
void OnSessionFinalized();
@@ -43,8 +41,8 @@ namespace ams::kern {
constexpr const KPort *GetParent() const { return m_parent; }
ALWAYS_INLINE s32 GetNumSessions() const { return m_num_sessions.Load(); }
ALWAYS_INLINE s32 GetPeakSessions() const { return m_peak_sessions.Load(); }
ALWAYS_INLINE s32 GetNumSessions() const { return m_num_sessions; }
ALWAYS_INLINE s32 GetPeakSessions() const { return m_peak_sessions; }
ALWAYS_INLINE s32 GetMaxSessions() const { return m_max_sessions; }
bool IsLight() const;

View File

@@ -27,8 +27,7 @@ namespace ams::kern {
private:
KSession *m_parent;
public:
constexpr explicit KClientSession(util::ConstantInitializeTag) : KAutoObject(util::ConstantInitialize), m_parent() { /* ... */ }
explicit KClientSession() { /* ... */ }
constexpr KClientSession() : m_parent() { /* ... */ }
void Initialize(KSession *parent) {
/* Set member variables. */
@@ -36,6 +35,7 @@ namespace ams::kern {
}
virtual void Destroy() override;
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
constexpr KSession *GetParent() const { return m_parent; }

View File

@@ -36,14 +36,14 @@ namespace ams::kern {
}
Result Initialize(KProcessAddress address, size_t size);
void Finalize();
virtual void Finalize() override;
Result Map(KProcessAddress address, size_t size);
Result Unmap(KProcessAddress address, size_t size);
Result MapToOwner(KProcessAddress address, size_t size, ams::svc::MemoryPermission perm);
Result UnmapFromOwner(KProcessAddress address, size_t size);
bool IsInitialized() const { return m_is_initialized; }
virtual bool IsInitialized() const override { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
KProcess *GetOwner() const { return m_owner; }

View File

@@ -26,7 +26,7 @@ namespace ams::kern {
private:
ThreadTree m_tree;
public:
constexpr KConditionVariable() = default;
constexpr KConditionVariable() : m_tree() { /* ... */ }
/* Arbitration. */
static Result SignalToAddress(KProcessAddress addr);

View File

@@ -25,20 +25,35 @@ namespace ams::kern {
class KDebugBase : public KSynchronizationObject {
protected:
using DebugEventList = util::IntrusiveListBaseTraits<KEventInfo>::ListType;
private:
class ProcessHolder {
private:
friend class KDebugBase;
private:
KProcess *m_process;
std::atomic<u32> m_ref_count;
private:
explicit ProcessHolder() : m_process(nullptr) { /* ... */ }
void Attach(KProcess *process);
void Detach();
bool Open();
void Close();
};
private:
DebugEventList m_event_info_list;
u32 m_continue_flags;
KSharedAutoObject<KProcess> m_process_holder;
ProcessHolder m_process_holder;
KLightLock m_lock;
KProcess::State m_old_process_state;
bool m_is_attached;
public:
explicit KDebugBase() { /* ... */ }
explicit KDebugBase() : m_event_info_list(), m_process_holder(), m_lock() { /* ... */ }
protected:
bool Is64Bit() const;
public:
void Initialize();
void Finalize();
Result Attach(KProcess *process);
Result BreakProcess();
@@ -53,6 +68,9 @@ namespace ams::kern {
Result GetThreadContext(ams::svc::ThreadContext *out, u64 thread_id, u32 context_flags);
Result SetThreadContext(const ams::svc::ThreadContext &ctx, u64 thread_id, u32 context_flags);
virtual Result GetThreadContextImpl(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags) = 0;
virtual Result SetThreadContextImpl(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags) = 0;
Result GetRunningThreadInfo(ams::svc::LastThreadContext *out_context, u64 *out_thread_id);
Result GetDebugEventInfo(ams::svc::lp64::DebugEventInfo *out);
@@ -71,7 +89,7 @@ namespace ams::kern {
}
ALWAYS_INLINE KProcess *GetProcessUnsafe() const {
return m_process_holder.Get();
return m_process_holder.m_process;
}
private:
void PushDebugEvent(ams::svc::DebugEvent event, uintptr_t param0 = 0, uintptr_t param1 = 0, uintptr_t param2 = 0, uintptr_t param3 = 0, uintptr_t param4 = 0);
@@ -80,10 +98,8 @@ namespace ams::kern {
template<typename T> requires (std::same_as<T, ams::svc::lp64::DebugEventInfo> || std::same_as<T, ams::svc::ilp32::DebugEventInfo>)
Result GetDebugEventInfoImpl(T *out);
public:
virtual void OnFinalizeSynchronizationObject() override;
virtual bool IsSignaled() const override;
private:
/* NOTE: This is public/virtual override in Nintendo's kernel. */
void OnFinalizeSynchronizationObject();
private:
static Result ProcessDebugEvent(ams::svc::DebugEvent event, uintptr_t param0, uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4);
public:

View File

@@ -30,12 +30,12 @@ namespace ams::kern {
u64 m_space_size;
bool m_is_initialized;
public:
explicit KDeviceAddressSpace() : m_is_initialized(false) { /* ... */ }
constexpr KDeviceAddressSpace() : m_lock(), m_table(), m_space_address(), m_space_size(), m_is_initialized() { /* ... */ }
Result Initialize(u64 address, u64 size);
void Finalize();
virtual void Finalize() override;
bool IsInitialized() const { return m_is_initialized; }
virtual bool IsInitialized() const override { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
Result Attach(ams::svc::DeviceName device_name);

View File

@@ -40,7 +40,7 @@ namespace ams::kern {
KVirtualAddress m_address;
size_t m_size;
public:
KDynamicPageManager() : m_lock(), m_page_bitmap(), m_used(), m_peak(), m_count(), m_address(Null<KVirtualAddress>), m_size() { /* ... */ }
KDynamicPageManager() : m_lock(), m_page_bitmap(), m_used(), m_peak(), m_count(), m_address(), m_size() { /* ... */ }
Result Initialize(KVirtualAddress memory, size_t sz) {
/* We need to have positive size. */

View File

@@ -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);
}
};

View File

@@ -29,19 +29,19 @@ namespace ams::kern {
private:
using PageBuffer = KDynamicPageManager::PageBuffer;
private:
util::Atomic<size_t> m_used{0};
util::Atomic<size_t> m_peak{0};
util::Atomic<size_t> m_count{0};
KVirtualAddress m_address{Null<KVirtualAddress>};
std::atomic<size_t> m_used{};
std::atomic<size_t> m_peak{};
std::atomic<size_t> m_count{};
KVirtualAddress m_address{};
size_t m_size{};
public:
constexpr KDynamicSlabHeap() = default;
constexpr ALWAYS_INLINE KVirtualAddress GetAddress() const { return m_address; }
constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; }
constexpr ALWAYS_INLINE size_t GetUsed() const { return m_used.Load(); }
constexpr ALWAYS_INLINE size_t GetPeak() const { return m_peak.Load(); }
constexpr ALWAYS_INLINE size_t GetCount() const { return m_count.Load(); }
constexpr ALWAYS_INLINE size_t GetUsed() const { return m_used.load(); }
constexpr ALWAYS_INLINE size_t GetPeak() const { return m_peak.load(); }
constexpr ALWAYS_INLINE size_t GetCount() const { return m_count.load(); }
constexpr ALWAYS_INLINE bool IsInRange(KVirtualAddress addr) const {
return this->GetAddress() <= addr && addr <= this->GetAddress() + this->GetSize() - 1;
@@ -58,7 +58,7 @@ namespace ams::kern {
KSlabHeapImpl::Initialize();
/* Allocate until we have the correct number of objects. */
while (m_count.Load() < num_objects) {
while (m_count.load() < num_objects) {
auto *allocated = reinterpret_cast<T *>(page_allocator->Allocate());
MESOSPHERE_ABORT_UNLESS(allocated != nullptr);
@@ -66,7 +66,7 @@ namespace ams::kern {
KSlabHeapImpl::Free(allocated + i);
}
m_count += sizeof(PageBuffer) / sizeof(T);
m_count.fetch_add(sizeof(PageBuffer) / sizeof(T));
}
}
@@ -89,7 +89,7 @@ namespace ams::kern {
for (size_t i = 1; i < sizeof(PageBuffer) / sizeof(T); i++) {
KSlabHeapImpl::Free(allocated + i);
}
m_count += sizeof(PageBuffer) / sizeof(T);
m_count.fetch_add(sizeof(PageBuffer) / sizeof(T));
}
}
}
@@ -99,10 +99,10 @@ namespace ams::kern {
std::construct_at(allocated);
/* Update our tracking. */
const size_t used = ++m_used;
size_t peak = m_peak.Load();
size_t used = m_used.fetch_add(1) + 1;
size_t peak = m_peak.load();
while (peak < used) {
if (m_peak.CompareExchangeWeak<std::memory_order_relaxed>(peak, used)) {
if (m_peak.compare_exchange_weak(peak, used, std::memory_order_relaxed)) {
break;
}
}
@@ -113,7 +113,7 @@ namespace ams::kern {
ALWAYS_INLINE void Free(T *t) {
KSlabHeapImpl::Free(t);
--m_used;
m_used.fetch_sub(1);
}
};

View File

@@ -29,24 +29,21 @@ namespace ams::kern {
bool m_initialized;
bool m_readable_event_destroyed;
public:
constexpr explicit KEvent(util::ConstantInitializeTag)
: KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList, true>(util::ConstantInitialize),
m_readable_event(util::ConstantInitialize), m_owner(), m_initialized(), m_readable_event_destroyed()
constexpr KEvent()
: m_readable_event(), m_owner(), m_initialized(), m_readable_event_destroyed()
{
/* ... */
}
explicit KEvent() : m_readable_event(), m_owner(), m_initialized(), m_readable_event_destroyed() { /* ... */ }
void Initialize();
void Finalize();
virtual void Finalize() override;
bool IsInitialized() const { return m_initialized; }
uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_owner); }
virtual bool IsInitialized() const override { return m_initialized; }
virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(m_owner); }
static void PostDestroy(uintptr_t arg);
KProcess *GetOwner() const { return m_owner; }
virtual KProcess *GetOwner() const override { return m_owner; }
KReadableEvent &GetReadableEvent() { return m_readable_event; }

View File

@@ -63,16 +63,16 @@ namespace ams::kern {
private:
EntryInfo m_entry_infos[MaxTableSize];
KAutoObject *m_objects[MaxTableSize];
mutable KSpinLock m_lock;
s32 m_free_head_index;
u16 m_table_size;
u16 m_max_count;
u16 m_next_linear_id;
u16 m_count;
mutable KSpinLock m_lock;
public:
constexpr explicit KHandleTable(util::ConstantInitializeTag) : m_entry_infos(), m_objects(), m_lock(), m_free_head_index(-1), m_table_size(), m_max_count(), m_next_linear_id(MinLinearId), m_count() { /* ... */ }
explicit KHandleTable() : m_lock(), m_free_head_index(-1), m_count() { MESOSPHERE_ASSERT_THIS(); }
constexpr KHandleTable() :
m_entry_infos(), m_objects(), m_free_head_index(-1), m_table_size(0), m_max_count(0), m_next_linear_id(MinLinearId), m_count(0), m_lock()
{ MESOSPHERE_ASSERT_THIS(); }
constexpr NOINLINE Result Initialize(s32 size) {
MESOSPHERE_ASSERT_THIS();

View File

@@ -31,25 +31,14 @@ namespace ams::kern {
s32 m_core_id;
bool m_is_initialized;
public:
constexpr explicit KInterruptEvent(util::ConstantInitializeTag) : KAutoObjectWithSlabHeapAndContainer<KInterruptEvent, KReadableEvent>(util::ConstantInitialize), m_interrupt_id(-1), m_core_id(-1), m_is_initialized(false) { /* ... */ }
explicit KInterruptEvent() : m_interrupt_id(-1), m_is_initialized(false) { /* ... */ }
constexpr KInterruptEvent() : m_interrupt_id(-1), m_core_id(-1), m_is_initialized(false) { /* ... */ }
Result Initialize(int32_t interrupt_name, ams::svc::InterruptType type);
void Finalize();
virtual void Finalize() override;
Result Reset();
virtual Result Reset() override;
Result Clear() {
MESOSPHERE_ASSERT_THIS();
/* Try to perform a reset, succeeding unconditionally. */
this->Reset();
return ResultSuccess();
}
bool IsInitialized() const { return m_is_initialized; }
virtual bool IsInitialized() const override { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }

View File

@@ -33,14 +33,14 @@ namespace ams::kern {
public:
static bool IsValidIoPoolType(ams::svc::IoPoolType pool_type);
public:
explicit KIoPool() : m_is_initialized(false) {
explicit KIoPool() : m_lock(), m_io_region_list(), m_is_initialized(false) {
/* ... */
}
Result Initialize(ams::svc::IoPoolType pool_type);
void Finalize();
virtual void Finalize() override;
bool IsInitialized() const { return m_is_initialized; }
virtual bool IsInitialized() const override { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
Result AddIoRegion(KIoRegion *region);

View File

@@ -40,12 +40,16 @@ namespace ams::kern {
util::IntrusiveListNode m_process_list_node;
util::IntrusiveListNode m_pool_list_node;
public:
explicit KIoRegion() : m_pool(nullptr), m_is_initialized(false) { /* ... */ }
explicit KIoRegion()
: m_lock(), m_pool(nullptr), m_is_initialized(false), m_process_list_node(), m_pool_list_node()
{
/* ... */
}
Result Initialize(KIoPool *pool, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm);
void Finalize();
virtual void Finalize() override;
bool IsInitialized() const { return m_is_initialized; }
virtual bool IsInitialized() const override { return m_is_initialized; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);

View File

@@ -26,7 +26,7 @@ namespace ams::kern {
private:
KLightSession *m_parent;
public:
explicit KLightClientSession() { /* ... */ }
constexpr KLightClientSession() : m_parent() { /* ... */ }
void Initialize(KLightSession *parent) {
/* Set member variables. */
@@ -34,6 +34,7 @@ namespace ams::kern {
}
virtual void Destroy() override;
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
constexpr const KLightSession *GetParent() const { return m_parent; }

View File

@@ -26,9 +26,7 @@ namespace ams::kern {
private:
KThread::WaiterList m_wait_list;
public:
constexpr explicit ALWAYS_INLINE KLightConditionVariable(util::ConstantInitializeTag) : m_wait_list() { /* ... */ }
explicit ALWAYS_INLINE KLightConditionVariable() { /* ... */ }
constexpr ALWAYS_INLINE KLightConditionVariable() : m_wait_list() { /* ... */ }
public:
void Wait(KLightLock *lock, s64 timeout = -1ll, bool allow_terminating_thread = true);
void Broadcast();

View File

@@ -23,25 +23,30 @@ namespace ams::kern {
class KLightLock {
private:
util::Atomic<uintptr_t> m_tag;
std::atomic<uintptr_t> m_tag;
public:
constexpr ALWAYS_INLINE KLightLock() : m_tag(0) { /* ... */ }
constexpr KLightLock() : m_tag(0) { /* ... */ }
void Lock() {
MESOSPHERE_ASSERT_THIS();
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer());
const uintptr_t cur_thread_tag = (cur_thread | 1);
while (true) {
uintptr_t old_tag = m_tag.Load<std::memory_order_relaxed>();
uintptr_t old_tag = m_tag.load(std::memory_order_relaxed);
while (!m_tag.CompareExchangeWeak<std::memory_order_acquire>(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1))) {
/* ... */
while (!m_tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : old_tag | 1, std::memory_order_acquire)) {
if ((old_tag | 1) == cur_thread_tag) {
return;
}
}
if (old_tag == 0 || this->LockSlowPath(old_tag | 1, cur_thread)) {
if ((old_tag == 0) || ((old_tag | 1) == cur_thread_tag)) {
break;
}
this->LockSlowPath(old_tag | 1, cur_thread);
}
}
@@ -49,18 +54,19 @@ namespace ams::kern {
MESOSPHERE_ASSERT_THIS();
const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer());
uintptr_t expected = cur_thread;
if (!m_tag.CompareExchangeStrong<std::memory_order_release>(expected, 0)) {
this->UnlockSlowPath(cur_thread);
}
do {
if (expected != cur_thread) {
return this->UnlockSlowPath(cur_thread);
}
} while (!m_tag.compare_exchange_weak(expected, 0, std::memory_order_release));
}
bool LockSlowPath(uintptr_t owner, uintptr_t cur_thread);
void LockSlowPath(uintptr_t owner, uintptr_t cur_thread);
void UnlockSlowPath(uintptr_t cur_thread);
ALWAYS_INLINE bool IsLocked() const { return m_tag.Load() != 0; }
ALWAYS_INLINE bool IsLockedByCurrentThread() const { return (m_tag.Load() | 0x1ul) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer()) | 0x1ul); }
ALWAYS_INLINE bool IsLocked() const { return m_tag.load() != 0; }
ALWAYS_INLINE bool IsLockedByCurrentThread() const { return (m_tag.load() | 0x1ul) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer()) | 0x1ul); }
};
using KScopedLightLock = KScopedLock<KLightLock>;

View File

@@ -32,7 +32,7 @@ namespace ams::kern {
u64 m_server_thread_id;
KThread *m_server_thread;
public:
explicit KLightServerSession() : m_current_request(nullptr), m_server_thread_id(std::numeric_limits<u64>::max()), m_server_thread() { /* ... */ }
constexpr KLightServerSession() : m_parent(), m_request_list(), m_current_request(), m_server_thread_id(), m_server_thread() { /* ... */ }
void Initialize(KLightSession *parent) {
/* Set member variables. */
@@ -40,6 +40,7 @@ namespace ams::kern {
}
virtual void Destroy() override;
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
constexpr const KLightSession *GetParent() const { return m_parent; }

Some files were not shown because too many files have changed in this diff Show More