Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80cae0cc2d | ||
|
|
e780171c78 | ||
|
|
0cbf726479 | ||
|
|
a192ca5172 | ||
|
|
cbebfcb9e2 | ||
|
|
ec950d8320 | ||
|
|
d562bb841d | ||
|
|
ff1760fac1 | ||
|
|
7ea4737abb | ||
|
|
0a1ce6f079 |
@@ -1,43 +1,4 @@
|
||||
# Changelog
|
||||
## 1.2.1
|
||||
+ Support was implemented for 13.1.0.
|
||||
+ `mesosphère` was updated to reflect the kernel behavioral changes made in 13.1.0.
|
||||
+ KScheduler now issues a data memory barrier when unlocking the scheduler lock and when early-returning due to top-thread-is-current during scheduling.
|
||||
+ `erpt` was updated to reflect the latest official behaviors.
|
||||
+ The new service added in 13.0.0 ("sprofile") was revised, and the data formats it expects was changed.
|
||||
+ This still appears to be (possibly(?)) untestable due to data not being transmitted yet, but I have greater confidence things will go smoothly than I did when 1.1.0 released.
|
||||
+ A number of improvements were made to `mesosphère`, including:
|
||||
+ A build target was created to build targeting the qemu `virt` board.
|
||||
+ This facilitates writing unit tests for the kernel (and other atmosphere components) and running them under PC.
|
||||
+ **Please Note**: Official system software will not work at all under this, and the Atmosphère project has zero interest in attempting to run official software of any kind. This is unit testing machinery, and explicitly not more than that.
|
||||
+ This should hopefully allow us to have greater confidence that all of atmosphere's components work the way they're theoretically supposed to in the future.
|
||||
+ **Please Note**: If you are a developer who is familiar with the Horizon operating system (or capable of becoming familiar), I would greatly appreciate help writing tests and improving the testing framework.
|
||||
+ Please contact `SciresM#0524` if you are capable and interested.
|
||||
+ Really, if you are actually a developer who would like to help me get this off the ground, I would deeply appreciate it.
|
||||
+ That said, if you are not a developer but want to be one, this probably isn't the best opportunity; I expect it to be highly technical.
|
||||
+ Consider the ReSwitched discord's #hack-n-all channel for your educational purposes.
|
||||
+ We are (at least for now) using [catch2](https://github.com/catchorg/Catch2) for unit tests.
|
||||
+ Almost all virtual calls in the kernel are now resolved statically.
|
||||
+ This eliminates substantial virtual call overhead, and should lead to improved kernel microperformance in pretty much every function.
|
||||
+ The remaining red black tree find operations which weren't using the optimized "find key" variant are now using the optimized version.
|
||||
+ Custom assembly was written to improve tick-to-timespan conversion.
|
||||
+ This works around gcc emitting suboptimal assembly at -Os (it emits good assembly at -O3, clang is fine at both -O3 and -Os).
|
||||
+ KThread and KSession structures were updated to optimize member layout, saving 0x10 bytes per KThread/KSession object.
|
||||
+ Rather than unnecessarily zero-ing all data in kernel objects only to overwrite members later, we now only initialize the members we need to in kernel object constructors.
|
||||
+ This is what Nintendo was doing already.
|
||||
+ A set of custom optimized atomic primitives were implemented and are used in place of std::atomic<>
|
||||
+ This works around a gcc bug which downgrades specified memory order to seq_cst, and introduces clrex in places where it is appropriate.
|
||||
+ This should strictly improve microperformance of many system calls.
|
||||
+ An compile-time toggleable extension was added to support 40-bit physical addresses in MapRange capabilities (using currently reserved bits).
|
||||
+ A number of minor bugs were fixed, including:
|
||||
+ Initial cache management now better reflects official behavior.
|
||||
+ This fixes an issue that caused certain hardware with cache sensitivity to produce cryptic kernel panics during boot.
|
||||
+ Incorrect logic when checking thread priority capabilities was fixed to reflect official behavior.
|
||||
+ The scheduler was updated to reflect latest official behavior, and a number of minor bugs involving clz/ctz were fixed.
|
||||
+ Accesses to the processes local region were fixed to properly use kernel linear region, not userland pointers.
|
||||
+ The cache SVCs exposed for 32-bit processes now better reflect official core mask request semantics.
|
||||
+ A bug was fixed that could cause a kernel panic if SvcArbitrateLock was called on a thread with exactly one reference in the middle of handling a user-mode exception.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 1.2.0
|
||||
+ `boot` was updated to reflect the latest official behavior for display/battery management.
|
||||
+ This should fix any issues that might result from running older releases on the OLED model, if you're somehow in a position to do so.
|
||||
|
||||
6
emummc/.gitrepo
vendored
6
emummc/.gitrepo
vendored
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/m4xw/emuMMC
|
||||
branch = develop
|
||||
commit = a9d56959460fc794ce2cb6405402c25a3e89c47f
|
||||
parent = ff719641396c635b735873fb2b020c910f768a04
|
||||
method = merge
|
||||
commit = f66087313546161a000ee196a788f0626caf80fa
|
||||
parent = 38f9a76ba028995ed3274da3a45b0254f09d1f59
|
||||
method = rebase
|
||||
cmdver = 0.4.1
|
||||
|
||||
16
emummc/README.md
vendored
16
emummc/README.md
vendored
@@ -1,21 +1,21 @@
|
||||
# emuMMC
|
||||
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
||||
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
||||
|
||||
### Supported Horizon Versions
|
||||
**1.0.0 - 13.1.0**
|
||||
**1.0.0 - 13.0.0**
|
||||
|
||||
## Features
|
||||
* Arbitrary SDMMC backend selection
|
||||
* Arbitrary SDMMC backend selection
|
||||
**This allows loading eMMC from SD or even SD from eMMC**
|
||||
* On the fly hooking / patching, fully self-infesting
|
||||
* On the fly hooking / patching, fully self-infesting
|
||||
**Only one payload required for all versions!**
|
||||
* File-based SDMMC backend support (from SD)
|
||||
* File-based SDMMC backend support (from SD)
|
||||
**This allows loading eMMC images from hekate-backups (split or not)**
|
||||
* SDMMC device based sector offset (*currently eMMC only*)
|
||||
* SDMMC device based sector offset (*currently eMMC only*)
|
||||
**Raw partition support for eMMC from SD with less performance overhead**
|
||||
* Full support for `/Nintendo` folder redirection to a arbitrary path
|
||||
* Full support for `/Nintendo` folder redirection to a arbitrary path
|
||||
**No 8 char length restriction!**
|
||||
* exosphere based context configuration
|
||||
* exosphere based context configuration
|
||||
**This includes full support for multiple emuMMC images**
|
||||
|
||||
## Compiling
|
||||
|
||||
8
emummc/source/FS/FS_offsets.c
vendored
8
emummc/source/FS/FS_offsets.c
vendored
@@ -57,8 +57,6 @@
|
||||
#include "offsets/1203_exfat.h"
|
||||
#include "offsets/1300.h"
|
||||
#include "offsets/1300_exfat.h"
|
||||
#include "offsets/1310.h"
|
||||
#include "offsets/1310_exfat.h"
|
||||
#include "../utils/fatal.h"
|
||||
|
||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
||||
@@ -127,8 +125,6 @@ DEFINE_OFFSET_STRUCT(_1203);
|
||||
DEFINE_OFFSET_STRUCT(_1203_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1300);
|
||||
DEFINE_OFFSET_STRUCT(_1300_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1310);
|
||||
DEFINE_OFFSET_STRUCT(_1310_EXFAT);
|
||||
|
||||
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
switch (version) {
|
||||
@@ -214,10 +210,6 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1300));
|
||||
case FS_VER_13_0_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1300_EXFAT));
|
||||
case FS_VER_13_1_0:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1310));
|
||||
case FS_VER_13_1_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1310_EXFAT));
|
||||
default:
|
||||
fatal_abort(Fatal_UnknownVersion);
|
||||
}
|
||||
|
||||
3
emummc/source/FS/FS_versions.h
vendored
3
emummc/source/FS/FS_versions.h
vendored
@@ -83,9 +83,6 @@ enum FS_VER
|
||||
FS_VER_13_0_0,
|
||||
FS_VER_13_0_0_EXFAT,
|
||||
|
||||
FS_VER_13_1_0,
|
||||
FS_VER_13_1_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
};
|
||||
|
||||
|
||||
59
emummc/source/FS/offsets/1310.h
vendored
59
emummc/source/FS/offsets/1310.h
vendored
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||
* Copyright (c) 2019 Atmosphere-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __FS_1310_H__
|
||||
#define __FS_1310_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1310_SDMMC_ACCESSOR_GC 0x158C20
|
||||
#define FS_OFFSET_1310_SDMMC_ACCESSOR_SD 0x15AA30
|
||||
#define FS_OFFSET_1310_SDMMC_ACCESSOR_NAND 0x159150
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1310_SDMMC_WRAPPER_READ 0x1545C0
|
||||
#define FS_OFFSET_1310_SDMMC_WRAPPER_WRITE 0x154680
|
||||
#define FS_OFFSET_1310_RTLD 0x688
|
||||
#define FS_OFFSET_1310_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||
|
||||
#define FS_OFFSET_1310_CLKRST_SET_MIN_V_CLK_RATE 0x1537C0
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1310_LOCK_MUTEX 0x29690
|
||||
#define FS_OFFSET_1310_UNLOCK_MUTEX 0x296E0
|
||||
|
||||
#define FS_OFFSET_1310_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1544A0
|
||||
#define FS_OFFSET_1310_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x154530
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1310_SD_MUTEX 0xE133E8
|
||||
#define FS_OFFSET_1310_NAND_MUTEX 0xE0E768
|
||||
#define FS_OFFSET_1310_ACTIVE_PARTITION 0xE0E7A8
|
||||
#define FS_OFFSET_1310_SDMMC_DAS_HANDLE 0xDF6E18
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1310_SD_DAS_INIT 0x27744
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1310_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006EBE0, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007BEEC, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00082294, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0009422C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1310_H__
|
||||
59
emummc/source/FS/offsets/1310_exfat.h
vendored
59
emummc/source/FS/offsets/1310_exfat.h
vendored
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||
* Copyright (c) 2019 Atmosphere-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __FS_1310_EXFAT_H__
|
||||
#define __FS_1310_EXFAT_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_ACCESSOR_GC 0x158C20
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_ACCESSOR_SD 0x15AA30
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_ACCESSOR_NAND 0x159150
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_READ 0x1545C0
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_WRITE 0x154680
|
||||
#define FS_OFFSET_1310_EXFAT_RTLD 0x688
|
||||
#define FS_OFFSET_1310_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x3C)))
|
||||
|
||||
#define FS_OFFSET_1310_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1537C0
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1310_EXFAT_LOCK_MUTEX 0x29690
|
||||
#define FS_OFFSET_1310_EXFAT_UNLOCK_MUTEX 0x296E0
|
||||
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x1544A0
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x154530
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1310_EXFAT_SD_MUTEX 0xE203E8
|
||||
#define FS_OFFSET_1310_EXFAT_NAND_MUTEX 0xE1B768
|
||||
#define FS_OFFSET_1310_EXFAT_ACTIVE_PARTITION 0xE1B7A8
|
||||
#define FS_OFFSET_1310_EXFAT_SDMMC_DAS_HANDLE 0xE03E18
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1310_EXFAT_SD_DAS_INIT 0x27744
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1310_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006EBE0, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007BEEC, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x00082294, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0009422C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1310_EXFAT_H__
|
||||
@@ -150,9 +150,6 @@ namespace ams::nxboot {
|
||||
FsVersion_13_0_0,
|
||||
FsVersion_13_0_0_Exfat,
|
||||
|
||||
FsVersion_13_1_0,
|
||||
FsVersion_13_1_0_Exfat,
|
||||
|
||||
FsVersion_Count,
|
||||
};
|
||||
|
||||
@@ -218,9 +215,6 @@ namespace ams::nxboot {
|
||||
|
||||
{ 0x7D, 0x20, 0x05, 0x47, 0x17, 0x8A, 0x83, 0x6A }, /* FsVersion_13_0_0 */
|
||||
{ 0x51, 0xEB, 0xFA, 0x9C, 0xCF, 0x66, 0xC0, 0x9E }, /* FsVersion_13_0_0_Exfat */
|
||||
|
||||
{ 0x91, 0xBA, 0x65, 0xA2, 0x1C, 0x1D, 0x50, 0xAE }, /* FsVersion_13_1_0 */
|
||||
{ 0x76, 0x38, 0x27, 0xEE, 0x9C, 0x20, 0x7E, 0x5B }, /* FsVersion_13_1_0_Exfat */
|
||||
};
|
||||
|
||||
const InitialProcessBinaryHeader *FindInitialProcessBinary(const pkg2::Package2Header *header, const u8 *data, ams::TargetFirmware target_firmware) {
|
||||
@@ -609,11 +603,6 @@ namespace ams::nxboot {
|
||||
AddPatch(fs_meta, 0x159119, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x1426D0, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
case FsVersion_13_1_0:
|
||||
case FsVersion_13_1_0_Exfat:
|
||||
AddPatch(fs_meta, 0x1590B9, NogcPatch0, sizeof(NogcPatch0));
|
||||
AddPatch(fs_meta, 0x142670, NogcPatch1, sizeof(NogcPatch1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||
branch = master
|
||||
commit = 13c6987cc43d0b9a874e87e3ce8eaffd1c72fa69
|
||||
parent = cb38b0b929f332a52ceeee5c27cb0fd83ff03433
|
||||
commit = cf765c0946cc5c828364ae6bfccddc4041304f28
|
||||
parent = 8634ea0f7c4f0e68adf2dfaaddc6ae1e225c4fc2
|
||||
method = merge
|
||||
cmdver = 0.4.1
|
||||
|
||||
@@ -52,10 +52,6 @@ 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");
|
||||
}
|
||||
|
||||
@@ -74,9 +74,6 @@ namespace ams::kern {
|
||||
|
||||
/* Release an instance of the lock. */
|
||||
if ((--m_lock_count) == 0) {
|
||||
/* Perform a memory barrier here. */
|
||||
cpu::DataMemoryBarrierInnerShareable();
|
||||
|
||||
/* We're no longer going to hold the lock. Take note of what cores need scheduling. */
|
||||
const u64 cores_needing_scheduling = SchedulerType::UpdateHighestPriorityThreads();
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace ams::kern::arch::arm64::cpu {
|
||||
} else {
|
||||
m_counter = cpu::GetPerformanceCounter(m_which);
|
||||
}
|
||||
DataMemoryBarrierInnerShareable();
|
||||
DataMemoryBarrier();
|
||||
m_done = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ namespace ams::kern {
|
||||
{
|
||||
const u32 has_waiter_flag = 1;
|
||||
WriteToUser(key, std::addressof(has_waiter_flag));
|
||||
cpu::DataMemoryBarrierInnerShareable();
|
||||
cpu::DataMemoryBarrier();
|
||||
}
|
||||
|
||||
/* Write the value to userspace. */
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace ams::sprofile::srv {
|
||||
constexpr const sm::ServiceName ServiceNameForSystemProcess = sm::ServiceName::Encode("sprof:sp");
|
||||
|
||||
constexpr inline size_t BgAgentSessionCountMax = 2;
|
||||
constexpr inline size_t SystemProcessSessionCountMax = 10;
|
||||
constexpr inline size_t SystemProcessSessionCountMax = 5;
|
||||
|
||||
constexpr inline size_t SessionCountMax = BgAgentSessionCountMax + SystemProcessSessionCountMax;
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace ams::sprofile::srv {
|
||||
|
||||
struct ServerManagerOptions {
|
||||
static constexpr size_t PointerBufferSize = 0x0;
|
||||
static constexpr size_t MaxDomains = SessionCountMax; /* NOTE: Official is 9 */
|
||||
static constexpr size_t MaxDomainObjects = 16; /* NOTE: Official is 14 */
|
||||
static constexpr size_t MaxDomains = SessionCountMax; /* NOTE: Official is 3 */
|
||||
static constexpr size_t MaxDomainObjects = 16; /* NOTE: Official is 8 */
|
||||
static constexpr bool CanDeferInvokeRequest = false;
|
||||
static constexpr bool CanManageMitmServers = false;
|
||||
};
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#include "sprofile_srv_types.hpp"
|
||||
|
||||
#define AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportProfile, (const sprofile::srv::ProfileDataForImportData &import), (import)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, Commit, (), ()) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, ImportMetadata, (const sprofile::srv::ProfileMetadataForImportMetadata &import), (import)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportProfile, (const sprofile::srv::ProfileDataForImportData &data), (data)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, Commit, (), ()) \
|
||||
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportMetadata, (const sprofile::srv::ProfileMetadataForImportMetadata &data), (data)) \
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileImporter, AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO)
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
AMS_SF_METHOD_INFO(C, H, 1, Result, GetUnsigned64, (sf::Out<u64> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, GetSigned32, (sf::Out<s32> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 3, Result, GetUnsigned32, (sf::Out<u32> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, GetByte, (sf::Out<u8> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key))
|
||||
AMS_SF_METHOD_INFO(C, H, 3, Result, GetByte, (sf::Out<u8> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key))
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileReader, AMS_SPROFILE_I_PROFILE_READER_INTERFACE_INFO)
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
#include "sprofile_srv_i_profile_importer.hpp"
|
||||
|
||||
#define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 200, Result, GetMetadataEntryData, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg), (out_count, out, arg)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ())
|
||||
AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 200, Result, ReadMetadata, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg), (out_count, out, arg)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ())
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(ams::sprofile, ISprofileServiceForBgAgent, AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO)
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace ams::sprofile::srv {
|
||||
bool HasProfile(Identifier id0, Identifier id1) {
|
||||
/* Require that we have metadata. */
|
||||
if (m_metadata.has_value()) {
|
||||
for (auto i = 0u; i < std::min<size_t>(m_metadata->num_entries, util::size(m_metadata->entries)); ++i) {
|
||||
for (auto i = 0u; i < m_metadata->num_entries; ++i) {
|
||||
const auto &entry = m_metadata->entries[i];
|
||||
if (entry.identifier_0 == id0 && entry.identifier_1 == id1) {
|
||||
return true;
|
||||
@@ -63,7 +63,7 @@ namespace ams::sprofile::srv {
|
||||
m_revision_key = meta.revision_key;
|
||||
|
||||
/* Import all profiles. */
|
||||
for (auto i = 0u; i < std::min<size_t>(meta.num_entries, util::size(meta.entries)); ++i) {
|
||||
for (auto i = 0u; i < meta.num_entries; ++i) {
|
||||
const auto &import_entry = meta.entries[i];
|
||||
if (!this->HasProfile(import_entry.identifier_0, import_entry.identifier_1)) {
|
||||
m_importing_profiles[m_importing_count++] = import_entry.identifier_0;
|
||||
|
||||
@@ -19,16 +19,16 @@
|
||||
|
||||
namespace ams::sprofile::srv {
|
||||
|
||||
Result ProfileImporterImpl::ImportProfile(const sprofile::srv::ProfileDataForImportData &import) {
|
||||
return m_manager->ImportProfile(import);
|
||||
Result ProfileImporterImpl::ImportProfile(const sprofile::srv::ProfileDataForImportData &data) {
|
||||
return m_manager->ImportProfile(data);
|
||||
}
|
||||
|
||||
Result ProfileImporterImpl::Commit() {
|
||||
return m_manager->Commit();
|
||||
}
|
||||
|
||||
Result ProfileImporterImpl::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &import) {
|
||||
return m_manager->ImportMetadata(import);
|
||||
Result ProfileImporterImpl::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data) {
|
||||
return m_manager->ImportMetadata(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace ams::sprofile::srv {
|
||||
public:
|
||||
ProfileImporterImpl(ProfileManager *manager) : m_manager(manager) { /* ... */ }
|
||||
public:
|
||||
Result ImportProfile(const sprofile::srv::ProfileDataForImportData &import);
|
||||
Result ImportProfile(const sprofile::srv::ProfileDataForImportData &data);
|
||||
Result Commit();
|
||||
Result ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &import);
|
||||
Result ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data);
|
||||
};
|
||||
static_assert(IsIProfileImporter<ProfileImporterImpl>);
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ namespace ams::sprofile::srv {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ProfileManager::ImportProfile(const sprofile::srv::ProfileDataForImportData &import) {
|
||||
Result ProfileManager::ImportProfile(const sprofile::srv::ProfileDataForImportData &data) {
|
||||
/* Acquire locks. */
|
||||
std::scoped_lock lk1(m_profile_importer_mutex);
|
||||
std::scoped_lock lk2(m_fs_mutex);
|
||||
@@ -159,37 +159,25 @@ namespace ams::sprofile::srv {
|
||||
/* Check that we have an importer. */
|
||||
R_UNLESS(m_profile_importer.has_value(), sprofile::ResultInvalidState());
|
||||
|
||||
/* Check that the metadata we're importing is a valid version. */
|
||||
R_UNLESS(IsValidProfileFormatVersion(import.header.version), sprofile::ResultInvalidDataVersion());
|
||||
|
||||
/* Check that the metadata we're importing has a valid hash. */
|
||||
{
|
||||
crypto::Md5Generator md5;
|
||||
md5.Update(std::addressof(import.header), sizeof(import.header));
|
||||
md5.Update(std::addressof(import.data), sizeof(import.data) - sizeof(import.data.entries[0]) * (util::size(import.data.entries) - std::min<size_t>(import.data.num_entries, util::size(import.data.entries))));
|
||||
|
||||
u8 hash[crypto::Md5Generator::HashSize];
|
||||
md5.GetHash(hash, sizeof(hash));
|
||||
|
||||
R_UNLESS(crypto::IsSameBytes(hash, import.hash, sizeof(hash)), sprofile::ResultInvalidDataHash());
|
||||
}
|
||||
/* Check that the metadata we're importing is valid. */
|
||||
R_UNLESS(data.data.version == ProfileDataVersion, sprofile::ResultInvalidDataVersion());
|
||||
|
||||
/* Succeed if we already have the profile. */
|
||||
R_SUCCEED_IF(m_profile_importer->HasProfile(import.header.identifier_0, import.header.identifier_1));
|
||||
R_SUCCEED_IF(m_profile_importer->HasProfile(data.identifier_0, data.identifier_1));
|
||||
|
||||
/* Check that we're importing the profile. */
|
||||
R_UNLESS(m_profile_importer->CanImportProfile(import.header.identifier_0), sprofile::ResultInvalidState());
|
||||
R_UNLESS(m_profile_importer->CanImportProfile(data.identifier_0), sprofile::ResultInvalidState());
|
||||
|
||||
/* Create temporary directories. */
|
||||
R_TRY(this->EnsureTemporaryDirectories());
|
||||
|
||||
/* Create profile. */
|
||||
char path[0x30];
|
||||
CreateTemporaryProfilePath(path, sizeof(path), m_save_data_info.mount_name, import.header.identifier_0);
|
||||
R_TRY(WriteFile(path, std::addressof(import.data), sizeof(import.data)));
|
||||
CreateTemporaryProfilePath(path, sizeof(path), m_save_data_info.mount_name, data.identifier_0);
|
||||
R_TRY(WriteFile(path, std::addressof(data.data), sizeof(data.data)));
|
||||
|
||||
/* Set profile imported. */
|
||||
m_profile_importer->OnImportProfile(import.header.identifier_0);
|
||||
m_profile_importer->OnImportProfile(data.identifier_0);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
@@ -243,7 +231,7 @@ namespace ams::sprofile::srv {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ProfileManager::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &import) {
|
||||
Result ProfileManager::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data) {
|
||||
/* Acquire locks. */
|
||||
std::scoped_lock lk1(m_profile_importer_mutex);
|
||||
std::scoped_lock lk2(m_fs_mutex);
|
||||
@@ -252,21 +240,8 @@ namespace ams::sprofile::srv {
|
||||
R_UNLESS(m_profile_importer.has_value(), sprofile::ResultInvalidState());
|
||||
R_UNLESS(m_profile_importer->CanImportMetadata(), sprofile::ResultInvalidState());
|
||||
|
||||
/* Check that the metadata we're importing is a valid version. */
|
||||
R_UNLESS(IsValidProfileFormatVersion(import.header.version), sprofile::ResultInvalidMetadataVersion());
|
||||
|
||||
/* Check that the metadata we're importing has a valid hash. */
|
||||
{
|
||||
crypto::Md5Generator md5;
|
||||
md5.Update(std::addressof(import.header), sizeof(import.header));
|
||||
md5.Update(std::addressof(import.metadata), sizeof(import.metadata));
|
||||
md5.Update(std::addressof(import.entries), sizeof(import.entries[0]) * std::min<size_t>(import.metadata.num_entries, util::size(import.metadata.entries)));
|
||||
|
||||
u8 hash[crypto::Md5Generator::HashSize];
|
||||
md5.GetHash(hash, sizeof(hash));
|
||||
|
||||
R_UNLESS(crypto::IsSameBytes(hash, import.hash, sizeof(hash)), sprofile::ResultInvalidMetadataHash());
|
||||
}
|
||||
/* Check that the metadata we're importing is valid. */
|
||||
R_UNLESS(data.metadata.version == ProfileMetadataVersion, sprofile::ResultInvalidMetadataVersion());
|
||||
|
||||
/* Create temporary directories. */
|
||||
R_TRY(this->EnsureTemporaryDirectories());
|
||||
@@ -274,10 +249,10 @@ namespace ams::sprofile::srv {
|
||||
/* Create metadata. */
|
||||
char path[0x30];
|
||||
CreateTemporaryMetadataPath(path, sizeof(path), m_save_data_info.mount_name);
|
||||
R_TRY(WriteFile(path, std::addressof(import.metadata), sizeof(import.metadata)));
|
||||
R_TRY(WriteFile(path, std::addressof(data.metadata), sizeof(data.metadata)));
|
||||
|
||||
/* Import the metadata. */
|
||||
m_profile_importer->ImportMetadata(import.metadata);
|
||||
m_profile_importer->ImportMetadata(data.metadata);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
@@ -334,13 +309,13 @@ namespace ams::sprofile::srv {
|
||||
std::scoped_lock lk2(m_general_mutex);
|
||||
|
||||
/* Load the desired profile. */
|
||||
if (R_SUCCEEDED(this->LoadProfile(profile))) {
|
||||
/* Find the specified key. */
|
||||
for (auto i = 0u; i < std::min<size_t>(m_service_profile->data.num_entries, util::size(m_service_profile->data.entries)); ++i) {
|
||||
if (m_service_profile->data.entries[i].key == key) {
|
||||
*out = m_service_profile->data.entries[i];
|
||||
return ResultSuccess();
|
||||
}
|
||||
R_TRY(this->LoadProfile(profile));
|
||||
|
||||
/* Find the specified key. */
|
||||
for (auto i = 0u; i < m_service_profile->data.num_entries; ++i) {
|
||||
if (m_service_profile->data.entries[i].key == key) {
|
||||
*out = m_service_profile->data.entries[i];
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,8 +426,6 @@ namespace ams::sprofile::srv {
|
||||
}
|
||||
|
||||
void ProfileManager::OnCommitted() {
|
||||
/* TODO: Here, Nintendo sets the erpt ServiceProfileRevisionKey to the current revision key. */
|
||||
|
||||
/* If we need to, invalidate the loaded service profile. */
|
||||
if (m_service_profile.has_value()) {
|
||||
for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) {
|
||||
@@ -463,6 +436,8 @@ namespace ams::sprofile::srv {
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Here, Nintendo sets the erpt ServiceProfileRevisionKey to the current revision key. */
|
||||
|
||||
/* Reset profile metadata. */
|
||||
m_profile_metadata = util::nullopt;
|
||||
|
||||
@@ -470,9 +445,6 @@ namespace ams::sprofile::srv {
|
||||
for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) {
|
||||
m_update_observer_manager.OnUpdate(m_profile_importer->GetImportingProfile(i));
|
||||
}
|
||||
|
||||
/* Reset profile importer. */
|
||||
m_profile_importer = util::nullopt;
|
||||
}
|
||||
|
||||
Result ProfileManager::EnsurePrimaryDirectories() {
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace ams::sprofile::srv {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ServiceForBgAgent::GetMetadataEntryData(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg) {
|
||||
Result ServiceForBgAgent::ReadMetadata(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg) {
|
||||
/* Check size. */
|
||||
R_UNLESS(out.GetSize() >= arg.metadata.num_entries, sprofile::ResultInvalidArgument());
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace ams::sprofile::srv {
|
||||
constexpr ServiceForBgAgent(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ }
|
||||
public:
|
||||
Result OpenProfileImporter(sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out);
|
||||
Result GetMetadataEntryData(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg);
|
||||
Result ReadMetadata(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg);
|
||||
Result IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key);
|
||||
Result Reset();
|
||||
};
|
||||
|
||||
@@ -18,11 +18,34 @@
|
||||
|
||||
namespace ams::sprofile::srv {
|
||||
|
||||
constexpr inline const u32 ProfileFormatVersion = 1;
|
||||
struct ProfileMetadataEntry {
|
||||
Identifier identifier_0;
|
||||
Identifier identifier_1;
|
||||
u8 unk_0E[0x32];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileMetadataEntry>::value);
|
||||
static_assert(sizeof(ProfileMetadataEntry) == 0x40);
|
||||
|
||||
constexpr inline bool IsValidProfileFormatVersion(u32 version) {
|
||||
return version == ProfileFormatVersion;
|
||||
}
|
||||
constexpr inline const u32 ProfileMetadataVersion = 0;
|
||||
|
||||
struct ProfileMetadata {
|
||||
u32 version;
|
||||
u32 num_entries;
|
||||
Identifier revision_key;
|
||||
u8 unk_10[0x30];
|
||||
ProfileMetadataEntry entries[50];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileMetadata>::value);
|
||||
static_assert(sizeof(ProfileMetadata) == 0xCC0);
|
||||
|
||||
struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
|
||||
ProfileMetadata metadata;
|
||||
u8 unk[0x8000 - sizeof(metadata)];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value);
|
||||
static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000);
|
||||
|
||||
constexpr inline const u32 ProfileDataVersion = 0;
|
||||
|
||||
enum ValueType : u8 {
|
||||
ValueType_Byte = 0,
|
||||
@@ -47,9 +70,9 @@ namespace ams::sprofile::srv {
|
||||
static_assert(sizeof(ProfileDataEntry) == 0x10);
|
||||
|
||||
struct ProfileData {
|
||||
u32 version;
|
||||
u32 num_entries;
|
||||
u8 unk_04[0x0C];
|
||||
u8 unk_10[0x20];
|
||||
u8 unk_08[0x28];
|
||||
ProfileDataEntry entries[(0x4000 - 0x30) / sizeof(ProfileDataEntry)];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileData>::value);
|
||||
@@ -63,55 +86,28 @@ namespace ams::sprofile::srv {
|
||||
static_assert(sizeof(ServiceProfile) == 0x4008);
|
||||
|
||||
struct ProfileDataForImportData : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
|
||||
struct {
|
||||
Identifier identifier_0;
|
||||
Identifier identifier_1;
|
||||
u8 unk_0E[2];
|
||||
u32 version;
|
||||
u8 unk_14[0x1C];
|
||||
} header;
|
||||
u8 hash[crypto::Md5Generator::HashSize];
|
||||
Identifier identifier_0;
|
||||
Identifier identifier_1;
|
||||
u8 unk_0E[2];
|
||||
ProfileData data;
|
||||
u8 unk_4040[0x4400 - 0x4040];
|
||||
u8 unk_4010[0x4400 - 0x4010];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileDataForImportData>::value);
|
||||
static_assert(sizeof(ProfileDataForImportData) == 0x4400);
|
||||
|
||||
struct ProfileMetadataEntry {
|
||||
Identifier identifier_0;
|
||||
Identifier identifier_1;
|
||||
u8 unk_0E[0x32];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileMetadataEntry>::value);
|
||||
static_assert(sizeof(ProfileMetadataEntry) == 0x40);
|
||||
|
||||
struct ProfileMetadataEntryData : public sf::PrefersMapAliasTransferMode {
|
||||
struct ReadMetadataEntry {
|
||||
u8 unk[0x100];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileMetadataEntryData>::value);
|
||||
static_assert(sizeof(ProfileMetadataEntryData) == 0x100);
|
||||
static_assert(util::is_pod<ReadMetadataEntry>::value);
|
||||
static_assert(sizeof(ReadMetadataEntry) == 0x100);
|
||||
|
||||
struct ProfileMetadata {
|
||||
u32 num_entries;
|
||||
u32 unk_04;
|
||||
Identifier revision_key;
|
||||
u8 unk_10[0x30];
|
||||
ProfileMetadataEntry entries[50];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileMetadata>::value);
|
||||
static_assert(sizeof(ProfileMetadata) == 0xCC0);
|
||||
|
||||
struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
|
||||
struct {
|
||||
u32 version;
|
||||
u8 unk_04[0x1C];
|
||||
} header;
|
||||
u8 hash[crypto::Md5Generator::HashSize];
|
||||
struct ReadMetadataArgument : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
|
||||
ProfileMetadata metadata;
|
||||
ProfileMetadataEntryData entries[50];
|
||||
u8 unk[0x8000 - 0x3EF0];
|
||||
ReadMetadataEntry entries[(0x8000 - sizeof(metadata)) / sizeof(ReadMetadataEntry)];
|
||||
u8 unk_7FC0[0x40];
|
||||
};
|
||||
static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value);
|
||||
static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000);
|
||||
static_assert(util::is_pod<ReadMetadataArgument>::value);
|
||||
static_assert(sizeof(ReadMetadataArgument) == 0x8000);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 2
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
|
||||
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 13
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
||||
|
||||
@@ -64,9 +64,8 @@
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_12_0_3 ATMOSPHERE_TARGET_FIRMWARE(12, 0, 3)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_12_1_0 ATMOSPHERE_TARGET_FIRMWARE(12, 1, 0)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_13_0_0 ATMOSPHERE_TARGET_FIRMWARE(13, 0, 0)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_13_1_0 ATMOSPHERE_TARGET_FIRMWARE(13, 1, 0)
|
||||
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_13_1_0
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_13_0_0
|
||||
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
||||
@@ -123,7 +122,6 @@ namespace ams {
|
||||
TargetFirmware_12_0_3 = ATMOSPHERE_TARGET_FIRMWARE_12_0_3,
|
||||
TargetFirmware_12_1_0 = ATMOSPHERE_TARGET_FIRMWARE_12_1_0,
|
||||
TargetFirmware_13_0_0 = ATMOSPHERE_TARGET_FIRMWARE_13_0_0,
|
||||
TargetFirmware_13_1_0 = ATMOSPHERE_TARGET_FIRMWARE_13_1_0,
|
||||
|
||||
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <vapours/crypto/crypto_memory_compare.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
#include <vapours/crypto/crypto_md5_generator.hpp>
|
||||
#include <vapours/crypto/crypto_sha1_generator.hpp>
|
||||
#include <vapours/crypto/crypto_sha256_generator.hpp>
|
||||
#include <vapours/crypto/crypto_aes_encryptor.hpp>
|
||||
|
||||
@@ -1,63 +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 <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_md5_impl.hpp>
|
||||
|
||||
namespace ams::crypto {
|
||||
|
||||
class Md5Generator {
|
||||
NON_COPYABLE(Md5Generator);
|
||||
NON_MOVEABLE(Md5Generator);
|
||||
private:
|
||||
using Impl = impl::Md5Impl;
|
||||
public:
|
||||
static constexpr size_t HashSize = Impl::HashSize;
|
||||
static constexpr size_t BlockSize = Impl::BlockSize;
|
||||
|
||||
static constexpr inline const u8 Asn1Identifier[] = {
|
||||
0x30, 0x20, /* Sequence, size 0x20 */
|
||||
0x30, 0x0C, /* Sequence, size 0x0C */
|
||||
0x06, 0x08, /* Object Identifier */
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* MD5 */
|
||||
0x05, 0x00, /* Null */
|
||||
0x04, 0x10, /* Octet string, size 0x10 */
|
||||
};
|
||||
static constexpr size_t Asn1IdentifierSize = util::size(Asn1Identifier);
|
||||
private:
|
||||
Impl m_impl;
|
||||
public:
|
||||
Md5Generator() { /* ... */ }
|
||||
|
||||
void Initialize() {
|
||||
m_impl.Initialize();
|
||||
}
|
||||
|
||||
void Update(const void *data, size_t size) {
|
||||
m_impl.Update(data, size);
|
||||
}
|
||||
|
||||
void GetHash(void *dst, size_t size) {
|
||||
m_impl.GetHash(dst, size);
|
||||
}
|
||||
};
|
||||
|
||||
void GenerateMd5Hash(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
|
||||
}
|
||||
@@ -1,61 +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 <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
class Md5Impl {
|
||||
public:
|
||||
static constexpr size_t HashSize = 0x10;
|
||||
static constexpr size_t BlockSize = 0x40;
|
||||
private:
|
||||
enum State {
|
||||
State_None = 0,
|
||||
State_Initialized = 1,
|
||||
State_Done = 2,
|
||||
};
|
||||
private:
|
||||
union {
|
||||
struct {
|
||||
u32 a, b, c, d;
|
||||
} p;
|
||||
u32 state[4];
|
||||
} m_x;
|
||||
alignas(8) u8 m_y[BlockSize];
|
||||
size_t m_size;
|
||||
State m_state;
|
||||
public:
|
||||
Md5Impl() : m_state(State_None) { /* ... */ }
|
||||
~Md5Impl() { ClearMemory(this, sizeof(*this)); }
|
||||
|
||||
void Initialize();
|
||||
void Update(const void *data, size_t size);
|
||||
void GetHash(void *dst, size_t size);
|
||||
private:
|
||||
void ProcessBlock();
|
||||
void ProcessLastBlock();
|
||||
};
|
||||
|
||||
/* static_assert(HashFunction<Md5Impl>); */
|
||||
|
||||
}
|
||||
@@ -37,8 +37,6 @@ namespace ams::sprofile {
|
||||
R_DEFINE_ERROR_RESULT(MaxObservers, 623);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(InvalidMetadataVersion, 3210);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMetadataHash, 3211);
|
||||
R_DEFINE_ERROR_RESULT(InvalidDataVersion, 3230);
|
||||
R_DEFINE_ERROR_RESULT(InvalidDataHash, 3231);
|
||||
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace ams::svc {
|
||||
}
|
||||
}
|
||||
|
||||
return util::ScaleByConstantFactorUp<s64, TicksPerSecond, NanoSecondsPerSecond>(ns);
|
||||
return util::ScaleByConstantFactor<s64, TicksPerSecond, NanoSecondsPerSecond>(ns);
|
||||
}
|
||||
public:
|
||||
constexpr ALWAYS_INLINE explicit Tick(s64 t = 0) : m_tick(t) { /* ... */ }
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace ams::svc {
|
||||
/* This is the highest SVC version supported by Atmosphere, to be updated on new kernel releases. */
|
||||
/* NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor. */
|
||||
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(13);
|
||||
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 4);
|
||||
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 3);
|
||||
|
||||
constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@ namespace ams::util {
|
||||
}
|
||||
|
||||
template<typename T, T N, T D>
|
||||
constexpr ALWAYS_INLINE T ScaleByConstantFactorUp(const T V) {
|
||||
constexpr ALWAYS_INLINE T ScaleByConstantFactor(const T V) {
|
||||
/* Multiplying and dividing by large numerator/denominator can cause error to be introduced. */
|
||||
/* This algorithm multiples/divides in stages, so as to mitigate this (particularly with large denominator). */
|
||||
|
||||
@@ -279,20 +279,4 @@ namespace ams::util {
|
||||
return (D * Quot_N * Quot_V) + (Quot_V * Rem_N) + (Rem_V * Quot_N) + rem_mult;
|
||||
}
|
||||
|
||||
template<std::integral T>
|
||||
constexpr ALWAYS_INLINE T RotateLeft(T v, int n) {
|
||||
using Unsigned = typename std::make_unsigned<T>::type;
|
||||
static_assert(sizeof(Unsigned) == sizeof(T));
|
||||
|
||||
return static_cast<T>(std::rotl<Unsigned>(static_cast<Unsigned>(v), n));
|
||||
}
|
||||
|
||||
template<std::integral T>
|
||||
constexpr ALWAYS_INLINE T RotateRight(T v, int n) {
|
||||
using Unsigned = typename std::make_unsigned<T>::type;
|
||||
static_assert(sizeof(Unsigned) == sizeof(T));
|
||||
|
||||
return static_cast<T>(std::rotr<Unsigned>(static_cast<Unsigned>(v), n));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
|
||||
namespace ams::util {
|
||||
|
||||
consteval bool IsLittleEndian() {
|
||||
constexpr bool IsLittleEndian() {
|
||||
return std::endian::native == std::endian::little;
|
||||
}
|
||||
|
||||
consteval bool IsBigEndian() {
|
||||
constexpr bool IsBigEndian() {
|
||||
return std::endian::native == std::endian::big;
|
||||
}
|
||||
|
||||
|
||||
@@ -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/>.
|
||||
*/
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::crypto {
|
||||
|
||||
void GenerateMd5Hash(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
Md5Generator gen;
|
||||
|
||||
gen.Initialize();
|
||||
gen.Update(src, src_size);
|
||||
gen.GetHash(dst, dst_size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,255 +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/>.
|
||||
*/
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Md5Constants {
|
||||
static constexpr const u32 A = 0x67452301;
|
||||
static constexpr const u32 B = 0xEFCDAB89;
|
||||
static constexpr const u32 C = 0x98BADCFE;
|
||||
static constexpr const u32 D = 0x10325476;
|
||||
|
||||
static constexpr const u32 T[] = {
|
||||
0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE,
|
||||
0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
|
||||
0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE,
|
||||
0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
|
||||
0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA,
|
||||
0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
|
||||
0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED,
|
||||
0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
|
||||
0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C,
|
||||
0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
|
||||
0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05,
|
||||
0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
|
||||
0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039,
|
||||
0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
|
||||
0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1,
|
||||
0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391,
|
||||
};
|
||||
|
||||
static constexpr u32 K[] = {
|
||||
0x1, 0x6, 0xB, 0x0,
|
||||
0x5, 0xA, 0xF, 0x4,
|
||||
0x9, 0xE, 0x3, 0x8,
|
||||
0xD, 0x2, 0x7, 0xC,
|
||||
0x5, 0x8, 0xB, 0xE,
|
||||
0x1, 0x4, 0x7, 0xA,
|
||||
0xD, 0x0, 0x3, 0x6,
|
||||
0x9, 0xC, 0xF, 0x2,
|
||||
0x0, 0x7, 0xE, 0x5,
|
||||
0xC, 0x3, 0xA, 0x1,
|
||||
0x8, 0xF, 0x6, 0xD,
|
||||
0x4, 0xB, 0x2, 0x9,
|
||||
};
|
||||
|
||||
static constexpr u8 Padding[] = {
|
||||
0x80
|
||||
};
|
||||
};
|
||||
|
||||
constexpr ALWAYS_INLINE u32 F(u32 x, u32 y, u32 z) { return (x & y) | ((~x) & z); }
|
||||
constexpr ALWAYS_INLINE u32 G(u32 x, u32 y, u32 z) { return (x & z) | (y & (~z)); }
|
||||
constexpr ALWAYS_INLINE u32 H(u32 x, u32 y, u32 z) { return x ^ y ^ z; }
|
||||
constexpr ALWAYS_INLINE u32 I(u32 x, u32 y, u32 z) { return y ^ (x | (~z)); }
|
||||
|
||||
constexpr ALWAYS_INLINE u32 CalculateRound1(u32 a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 t) { return b + util::RotateLeft<u32>(a + F(b, c, d) + x + t, s); }
|
||||
constexpr ALWAYS_INLINE u32 CalculateRound2(u32 a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 t) { return b + util::RotateLeft<u32>(a + G(b, c, d) + x + t, s); }
|
||||
constexpr ALWAYS_INLINE u32 CalculateRound3(u32 a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 t) { return b + util::RotateLeft<u32>(a + H(b, c, d) + x + t, s); }
|
||||
constexpr ALWAYS_INLINE u32 CalculateRound4(u32 a, u32 b, u32 c, u32 d, u32 x, u32 s, u32 t) { return b + util::RotateLeft<u32>(a + I(b, c, d) + x + t, s); }
|
||||
|
||||
void Encode(u32 *dst, const u32 *src, size_t size) {
|
||||
if constexpr (util::IsBigEndian()) {
|
||||
for (size_t i = 0; i < size; i += sizeof(u32)) {
|
||||
util::StoreLittleEndian(dst + i, src[i]);
|
||||
}
|
||||
} else {
|
||||
std::memcpy(dst, src, size);
|
||||
}
|
||||
}
|
||||
|
||||
void Decode(u32 *dst, const u32 *src, size_t size) {
|
||||
if constexpr (util::IsBigEndian()) {
|
||||
for (size_t i = 0; i < size; i += sizeof(u32)) {
|
||||
dst[i] = util::LoadLittleEndian(src + i);
|
||||
}
|
||||
} else {
|
||||
std::memcpy(dst, src, size);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Md5Impl::Initialize() {
|
||||
/* Set constants. */
|
||||
m_x.p.a = Md5Constants::A;
|
||||
m_x.p.b = Md5Constants::B;
|
||||
m_x.p.c = Md5Constants::C;
|
||||
m_x.p.d = Md5Constants::D;
|
||||
|
||||
/* Set size. */
|
||||
m_size = 0;
|
||||
|
||||
/* Set initialized. */
|
||||
m_state = State_Initialized;
|
||||
}
|
||||
|
||||
void Md5Impl::Update(const void *data, size_t size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_state == State_Initialized);
|
||||
|
||||
/* Determine how much we can process. */
|
||||
const size_t work_idx = m_size % BlockSize;
|
||||
const size_t work_remaining = BlockSize - work_idx;
|
||||
|
||||
/* Increment our size. */
|
||||
m_size += size;
|
||||
|
||||
/* Copy in the data to our buffer, if we don't have a full block. */
|
||||
if (work_remaining > size) {
|
||||
if (size > 0) {
|
||||
std::memcpy(m_y + work_idx, data, size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy what we can to complete our block. */
|
||||
std::memcpy(m_y + work_idx, data, work_remaining);
|
||||
|
||||
/* Process the block. */
|
||||
this->ProcessBlock();
|
||||
|
||||
/* Adjust size to account for what we've processed. */
|
||||
size -= work_remaining;
|
||||
|
||||
/* Process as many full blocks as we can. */
|
||||
const u8 *cur_block = static_cast<const u8 *>(data) + work_remaining;
|
||||
for (size_t i = 0; i < size / BlockSize; ++i) {
|
||||
std::memcpy(m_y, cur_block, BlockSize);
|
||||
cur_block += BlockSize;
|
||||
|
||||
this->ProcessBlock();
|
||||
}
|
||||
|
||||
/* Copy in any leftover data. */
|
||||
if (const auto left = size % BlockSize; left > 0) {
|
||||
std::memcpy(m_y, cur_block, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Md5Impl::GetHash(void *dst, size_t size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(m_state == State_Initialized || m_state == State_Done);
|
||||
AMS_ASSERT(size >= HashSize);
|
||||
AMS_UNUSED(size);
|
||||
|
||||
/* If we need to, finish processing. */
|
||||
if (m_state == State_Initialized) {
|
||||
this->ProcessLastBlock();
|
||||
m_state = State_Done;
|
||||
}
|
||||
|
||||
/* Encode the result. */
|
||||
Encode(static_cast<u32 *>(dst), m_x.state, HashSize);
|
||||
}
|
||||
|
||||
void Md5Impl::ProcessBlock() {
|
||||
/* Declare tracking pointers for rounds. */
|
||||
u32 x[BlockSize / sizeof(u32)];
|
||||
const u32 *p_t = Md5Constants::T;
|
||||
const u32 *p_k = Md5Constants::K;
|
||||
const u32 *p_x = x;
|
||||
|
||||
/* Extract current state. */
|
||||
u32 a = m_x.p.a;
|
||||
u32 b = m_x.p.b;
|
||||
u32 c = m_x.p.c;
|
||||
u32 d = m_x.p.d;
|
||||
|
||||
/* Decode the block into native endian. */
|
||||
Decode(x, reinterpret_cast<const u32 *>(m_y), BlockSize);
|
||||
|
||||
/* Perform round 1. */
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
a = CalculateRound1(a, b, c, d, *p_x++, 7, *p_t++);
|
||||
d = CalculateRound1(d, a, b, c, *p_x++, 12, *p_t++);
|
||||
c = CalculateRound1(c, d, a, b, *p_x++, 17, *p_t++);
|
||||
b = CalculateRound1(b, c, d, a, *p_x++, 22, *p_t++);
|
||||
}
|
||||
|
||||
/* Perform round 2. */
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
a = CalculateRound2(a, b, c, d, x[*p_k++], 5, *p_t++);
|
||||
d = CalculateRound2(d, a, b, c, x[*p_k++], 9, *p_t++);
|
||||
c = CalculateRound2(c, d, a, b, x[*p_k++], 14, *p_t++);
|
||||
b = CalculateRound2(b, c, d, a, x[*p_k++], 20, *p_t++);
|
||||
}
|
||||
|
||||
/* Perform round 3. */
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
a = CalculateRound3(a, b, c, d, x[*p_k++], 4, *p_t++);
|
||||
d = CalculateRound3(d, a, b, c, x[*p_k++], 11, *p_t++);
|
||||
c = CalculateRound3(c, d, a, b, x[*p_k++], 16, *p_t++);
|
||||
b = CalculateRound3(b, c, d, a, x[*p_k++], 23, *p_t++);
|
||||
}
|
||||
|
||||
/* Perform round 4. */
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
a = CalculateRound4(a, b, c, d, x[*p_k++], 6, *p_t++);
|
||||
d = CalculateRound4(d, a, b, c, x[*p_k++], 10, *p_t++);
|
||||
c = CalculateRound4(c, d, a, b, x[*p_k++], 15, *p_t++);
|
||||
b = CalculateRound4(b, c, d, a, x[*p_k++], 21, *p_t++);
|
||||
}
|
||||
|
||||
/* Mix the result back into our state. */
|
||||
m_x.p.a += a;
|
||||
m_x.p.b += b;
|
||||
m_x.p.c += c;
|
||||
m_x.p.d += d;
|
||||
}
|
||||
|
||||
void Md5Impl::ProcessLastBlock() {
|
||||
/* Get bit count. */
|
||||
const u64 bit_count = m_size * BITSIZEOF(u8);
|
||||
|
||||
/* Add padding byte unconditionally. */
|
||||
this->Update(Md5Constants::Padding, sizeof(Md5Constants::Padding));
|
||||
|
||||
/* Determine remaining. */
|
||||
size_t work_idx = m_size % BlockSize;
|
||||
size_t work_remaining = BlockSize - work_idx;
|
||||
|
||||
/* We want to process 8000.....{bit count}. */
|
||||
if (work_remaining < sizeof(u64)) {
|
||||
std::memset(m_y + work_idx, 0, work_remaining);
|
||||
this->ProcessBlock();
|
||||
work_idx = 0;
|
||||
work_remaining = BlockSize;
|
||||
}
|
||||
if (work_remaining > sizeof(u64)) {
|
||||
std::memset(m_y + work_idx, 0, work_remaining - sizeof(u64));
|
||||
}
|
||||
|
||||
util::StoreLittleEndian<u64>(reinterpret_cast<u64 *>(m_y + BlockSize - sizeof(u64)), bit_count);
|
||||
|
||||
this->ProcessBlock();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -126,8 +126,7 @@ _ZN3ams4kern10KScheduler12ScheduleImplEv:
|
||||
cmp x7, x18
|
||||
b.ne 1f
|
||||
|
||||
/* If they're the same, then we can just issue a memory barrier and return. */
|
||||
dmb ish
|
||||
/* If they're the same, then we can just return as there's nothing to do. */
|
||||
ret
|
||||
|
||||
0: /* The interrupt task thread is runnable. */
|
||||
|
||||
Reference in New Issue
Block a user