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
883 changed files with 17284 additions and 42458 deletions

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) + [Python 2](https://www.python.org) (Python 3 may work as well, but this is not guaranteed)
+ [LZ4](https://pypi.org/project/lz4) + [LZ4](https://pypi.org/project/lz4)
+ [PyCryptodome](https://pypi.org/project/pycryptodome) (optional) + [PyCryptodome](https://pypi.org/project/pycryptodome) (optional)
+ [hactool](https://github.com/SciresM/hactool)
## Instructions ## 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. 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` + `switch-libjpeg-turbo`
+ `devkitARM` + `devkitARM`
+ `devkitarm-rules` + `devkitarm-rules`
+ `hactool`
3. Install the following library via python's package manager `pip`, required by [exosphere](components/exosphere.md): 3. Install the following library via python's package manager `pip`, required by [exosphere](components/exosphere.md):
+ `lz4` + `lz4`

View File

@@ -1,38 +1,4 @@
# Changelog # Changelog
## 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 ## 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. + 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. + General system stability improvements to enhance the user's experience.

View File

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

View File

@@ -76,10 +76,10 @@ namespace ams::secmon::fatal {
Bit_Readable = 31, Bit_Readable = 31,
}; };
private: private:
u32 m_value; u32 value;
protected: protected:
constexpr ALWAYS_INLINE u32 SelectBit(Bit n) const { 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 { constexpr ALWAYS_INLINE bool GetBit(Bit n) const {
@@ -97,7 +97,7 @@ namespace ams::secmon::fatal {
ALWAYS_INLINE void SetValue(u32 v) { ALWAYS_INLINE void SetValue(u32 v) {
/* Prevent re-ordering around entry modifications. */ /* Prevent re-ordering around entry modifications. */
__asm__ __volatile__("" ::: "memory"); __asm__ __volatile__("" ::: "memory");
m_value = v; this->value = v;
__asm__ __volatile__("" ::: "memory"); __asm__ __volatile__("" ::: "memory");
} }
public: 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 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); } 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); const int prefix_len = std::strlen(automatic_backups_prefix);
for (size_t i = 0; i + prefix_len < f_ctx->stack_dump_size; ++i) { 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" 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"; "Please try running an archive bit fixer tool (for example, the one in Hekate).\n";
break; break;

View File

@@ -28,7 +28,7 @@ namespace ams::fs {
}; };
struct ReadOption { struct ReadOption {
u32 _value; u32 value;
static const ReadOption None; static const ReadOption None;
}; };
@@ -36,7 +36,7 @@ namespace ams::fs {
inline constexpr const ReadOption ReadOption::None = {0}; inline constexpr const ReadOption ReadOption::None = {0};
inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) { 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) { 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)); static_assert(util::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32));
struct WriteOption { struct WriteOption {
u32 _value; u32 value;
constexpr inline bool HasFlushFlag() const { constexpr inline bool HasFlushFlag() const {
return _value & 1; return this->value & 1;
} }
static const WriteOption None; static const WriteOption None;
@@ -60,7 +60,7 @@ namespace ams::fs {
inline constexpr const WriteOption WriteOption::Flush = {1}; inline constexpr const WriteOption WriteOption::Flush = {1};
inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) { 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) { 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(); 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. */ /* Acquire exclusive access to exception handling logic. */
if (!g_is_locked.Exchange(true)) { if (!g_is_locked.exchange(true)) {
/* Invoke the exception handler impl. */ /* Invoke the exception handler impl. */
ExceptionHandlerImpl(lr, sp); ExceptionHandlerImpl(lr, sp);

View File

@@ -23,16 +23,16 @@ namespace ams::secmon {
void *PageMapperImpl::GetPointerTo(uintptr_t phys, size_t size) const { void *PageMapperImpl::GetPointerTo(uintptr_t phys, size_t size) const {
/* Ensure we stay within the page. */ /* 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; return nullptr;
} }
if (size != 0) { 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 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 { 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 { class PageMapperImpl {
private: private:
uintptr_t m_physical_address; uintptr_t physical_address;
uintptr_t m_virtual_address; uintptr_t virtual_address;
public: 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; void *GetPointerTo(uintptr_t phys, size_t size) const;
@@ -37,14 +37,14 @@ namespace ams::secmon {
template<auto F> template<auto F>
bool MapImpl() { bool MapImpl() {
m_virtual_address = F(m_physical_address); this->virtual_address = F(this->physical_address);
return m_virtual_address != 0; return this->virtual_address != 0;
} }
template<auto F> template<auto F>
void UnmapImpl() { void UnmapImpl() {
F(); 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_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_Ctr: se::ComputeAes128CtrAsync(output_address, slot, input_address, size, iv, sizeof(iv), SecurityEngineDoneHandler); break;
case CipherMode_Cmac: case CipherMode_Cmac:
return SmcResult::NotSupported; return SmcResult::NotImplemented;
default: default:
return SmcResult::InvalidArgument; return SmcResult::InvalidArgument;
} }
@@ -765,8 +765,8 @@ namespace ams::secmon::smc {
const auto which = static_cast<SecureData>(args.r[1]); const auto which = static_cast<SecureData>(args.r[1]);
/* Validate arguments/conditions. */ /* Validate arguments/conditions. */
SMC_R_UNLESS(fuse::GetPatchVersion() < fuse::PatchVersion_Odnx02A2, NotSupported); SMC_R_UNLESS(fuse::GetPatchVersion() < fuse::PatchVersion_Odnx02A2, NotImplemented);
SMC_R_UNLESS(which < SecureData_Count, NotSupported); SMC_R_UNLESS(which < SecureData_Count, NotImplemented);
/* Use a temporary buffer. */ /* Use a temporary buffer. */
u8 secure_data[AesKeySize]; u8 secure_data[AesKeySize];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,14 +22,14 @@ namespace ams::nxboot::loader {
class Lz4Uncompressor { class Lz4Uncompressor {
private: private:
const u8 *m_src; const u8 *src;
size_t m_src_size; size_t src_size;
size_t m_src_offset; size_t src_offset;
u8 *m_dst; u8 *dst;
size_t m_dst_size; size_t dst_size;
size_t m_dst_offset; size_t dst_offset;
public: 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)); this->Copy(this->GetCopySize(control >> 4));
/* If we've exceeded size, we're done. */ /* If we've exceeded size, we're done. */
if (m_src_offset >= m_src_size) { if (this->src_offset >= this->src_size) {
break; break;
} }
@@ -55,21 +55,21 @@ namespace ams::nxboot::loader {
const size_t wide_copy_size = this->GetCopySize(control & 0xF); const size_t wide_copy_size = this->GetCopySize(control & 0xF);
/* Copy bytes. */ /* Copy bytes. */
const size_t end_offset = m_dst_offset + wide_copy_size + 4; const size_t end_offset = this->dst_offset + wide_copy_size + 4;
for (size_t cur_offset = m_dst_offset; cur_offset < end_offset; m_dst_offset = (++cur_offset)) { for (size_t cur_offset = this->dst_offset; cur_offset < end_offset; this->dst_offset = (++cur_offset)) {
AMS_ABORT_UNLESS(wide_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: private:
u8 ReadByte() { u8 ReadByte() {
return m_src[m_src_offset++]; return this->src[this->src_offset++];
} }
bool CanRead() const { bool CanRead() const {
return m_src_offset < m_src_size; return this->src_offset < this->src_size;
} }
size_t GetCopySize(u8 control) { size_t GetCopySize(u8 control) {
@@ -87,9 +87,11 @@ namespace ams::nxboot::loader {
} }
void Copy(size_t size) { void Copy(size_t size) {
__builtin_memcpy(m_dst + m_dst_offset, m_src + m_src_offset, size); for (size_t i = 0; i < size; ++i) {
m_dst_offset += size; this->dst[this->dst_offset + i] = this->src[this->src_offset + i];
m_src_offset += size; }
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) { 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) { 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; constexpr size_t MaxDirectories = 2;
constinit bool g_is_sd_mounted = false; 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_sd_fs = {};
alignas(0x10) constinit FATFS g_sys_fs = {};
alignas(0x10) constinit FIL g_files[MaxFiles] = {}; alignas(0x10) constinit FIL g_files[MaxFiles] = {};
alignas(0x10) constinit DIR g_dirs[MaxDirectories] = {}; alignas(0x10) constinit DIR g_dirs[MaxDirectories] = {};
@@ -129,6 +131,18 @@ namespace ams::fs {
g_is_sd_mounted = false; 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) { Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path) {
/* Get the file info. */ /* Get the file info. */
FILINFO info; FILINFO info;

View File

@@ -28,7 +28,7 @@ namespace ams::fs {
}; };
struct ReadOption { struct ReadOption {
u32 _value; u32 value;
static const ReadOption None; static const ReadOption None;
}; };
@@ -36,7 +36,7 @@ namespace ams::fs {
inline constexpr const ReadOption ReadOption::None = {0}; inline constexpr const ReadOption ReadOption::None = {0};
inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) { 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) { 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)); static_assert(util::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32));
struct WriteOption { struct WriteOption {
u32 _value; u32 value;
constexpr inline bool HasFlushFlag() const { constexpr inline bool HasFlushFlag() const {
return _value & 1; return this->value & 1;
} }
static const WriteOption None; static const WriteOption None;
@@ -60,7 +60,7 @@ namespace ams::fs {
inline constexpr const WriteOption WriteOption::Flush = {1}; inline constexpr const WriteOption WriteOption::Flush = {1};
inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) { 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) { inline constexpr bool operator!=(const WriteOption &lhs, const WriteOption &rhs) {
@@ -98,6 +98,9 @@ namespace ams::fs {
bool MountSdCard(); bool MountSdCard();
void UnmountSdCard(); void UnmountSdCard();
bool MountSystem();
void UnmountSystem();
Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path); Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path);
Result CreateFile(const char *path, s64 size); 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_boot0_storage = nullptr;
constinit fs::IStorage *g_user_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; constinit fs::SubStorage *g_package2_storage = nullptr;
struct Guid { struct Guid {
@@ -227,6 +333,10 @@ namespace ams::nxboot {
}; };
static_assert(sizeof(Gpt) == 16_KB + 0x200); static_assert(sizeof(Gpt) == 16_KB + 0x200);
constexpr const u16 SystemPartitionName[] = {
'S', 'Y', 'S', 'T', 'E', 'M', 0
};
constexpr const u16 Package2PartitionName[] = { constexpr const u16 Package2PartitionName[] = {
'B', 'C', 'P', 'K', 'G', '2', '-', '1', '-', 'N', 'o', 'r', 'm', 'a', 'l', '-', 'M', 'a', 'i', 'n', 0 '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 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); 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); 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. */ /* Check that we created package2 storage. */
if (g_package2_storage == nullptr) { if (g_package2_storage == nullptr) {
ShowFatalError("Failed to initialize Package2\n"); 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) { Result ReadBoot0(s64 offset, void *dst, size_t size) {
@@ -356,4 +478,8 @@ namespace ams::nxboot {
return g_package2_storage->Read(offset, dst, size); 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 verif_hash;
u32 store_hash; u32 store_hash;
if (fuse::GetSocType() == fuse::SocType_Erista) { 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]; verif_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[-2];
store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(ExternalPackage{}.ovl_mtc_erista) / sizeof(u32)) - 1]; store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(ExternalPackage{}.ovl_mtc_erista) / sizeof(u32)) - 1];
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ { } 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]; verif_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[-1];
store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(ExternalPackage{}.ovl_mtc_mariko) / sizeof(u32)) - 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; 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; fs::DirectoryEntryType entry_type;
bool archive; bool archive;
return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_File; 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() { bool ConfigureEmummc() {
/* Set magic. */ /* Set magic. */
g_emummc_cfg.base_cfg.magic = secmon::EmummcBaseConfiguration::Magic; g_emummc_cfg.base_cfg.magic = secmon::EmummcBaseConfiguration::Magic;
@@ -146,7 +160,7 @@ namespace ams::nxboot {
/* Handle individual fields. */ /* Handle individual fields. */
for (const auto &entry : section.kv_list) { for (const auto &entry : section.kv_list) {
if (std::strcmp(entry.key, "enabled") == 0) { 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) { } else if (std::strcmp(entry.key, "id") == 0) {
id = ParseHexInteger(entry.value); id = ParseHexInteger(entry.value);
} else if (std::strcmp(entry.key, "sector") == 0) { } else if (std::strcmp(entry.key, "sector") == 0) {
@@ -206,56 +220,143 @@ namespace ams::nxboot {
return package1; return package1;
} }
ams::TargetFirmware GetApproximateTargetFirmware(const u8 *package1) { ams::TargetFirmware GetTargetFirmware(const u8 *package1) {
/* Get an approximation of the target firmware. */ /* Get first an approximation of the target firmware. */
ams::TargetFirmware target_firmware = ams::TargetFirmware_Current;
switch (package1[0x1F]) { switch (package1[0x1F]) {
case 0x01: case 0x01:
return ams::TargetFirmware_1_0_0; target_firmware = ams::TargetFirmware_1_0_0;
break;
case 0x02: case 0x02:
return ams::TargetFirmware_2_0_0; target_firmware = ams::TargetFirmware_2_0_0;
break;
case 0x04: case 0x04:
return ams::TargetFirmware_3_0_0; target_firmware = ams::TargetFirmware_3_0_0;
break;
case 0x07: case 0x07:
return ams::TargetFirmware_4_0_0; target_firmware = ams::TargetFirmware_4_0_0;
break;
case 0x0B: case 0x0B:
return ams::TargetFirmware_5_0_0; target_firmware = ams::TargetFirmware_5_0_0;
break;
case 0x0E: case 0x0E:
if (std::memcmp(package1 + 0x10, "20180802", 8) == 0) { 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) { } 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; break;
case 0x0F: case 0x0F:
return ams::TargetFirmware_7_0_0; target_firmware = ams::TargetFirmware_7_0_0;
break;
case 0x10: case 0x10:
if (std::memcmp(package1 + 0x10, "20190314", 8) == 0) { 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) { } 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) { } 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) { } 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) { } 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) { } 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) { } 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) { } 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) { } 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) { } 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; break;
default: default:
ShowFatalError("Unable to identify package1!\n");
break; 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() { u8 *LoadBootConfigAndPackage2() {
@@ -270,7 +371,7 @@ namespace ams::nxboot {
u8 *package2; u8 *package2;
size_t package2_size; 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; pkg2::Package2Header header;
if (R_FAILED((result = ReadPackage2(Package2Offset, std::addressof(header), sizeof(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); const u8 * const package1 = LoadPackage1(soc_type);
/* Get target firmware. */ /* Get target firmware. */
const auto target_firmware = GetApproximateTargetFirmware(package1); const auto target_firmware = GetTargetFirmware(package1);
/* Read/decrypt package2. */ /* Read/decrypt package2. */
u8 * const package2 = LoadBootConfigAndPackage2(); u8 * const package2 = LoadBootConfigAndPackage2();

View File

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

View File

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

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 \ -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector \
-Wno-format-truncation -Wno-format-zero-length -Wno-stringop-truncation -Wno-format-truncation -Wno-format-zero-length -Wno-stringop-truncation
export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++20
export ATMOSPHERE_CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++20 -Wno-invalid-offsetof
export ATMOSPHERE_ASFLAGS := export ATMOSPHERE_ASFLAGS :=
@@ -52,21 +51,6 @@ export ATMOSPHERE_OS_NAME := horizon
export ATMOSPHERE_CPU_EXTENSIONS := export ATMOSPHERE_CPU_EXTENSIONS :=
endif 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_CPU_EXTENSIONS := arm_crypto_extension aarch64_crypto_extension
endif
endif endif
ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57) ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57)

View File

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

View File

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

View File

@@ -70,10 +70,6 @@ namespace ams::secmon {
GetConfigurationContext().secmon_cfg.key_generation = generation; 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() { ALWAYS_INLINE pkg1::BootConfig *GetBootConfigStorage() {
return std::addressof(GetConfigurationContext().boot_config); return std::addressof(GetConfigurationContext().boot_config);
} }

View File

@@ -22,53 +22,52 @@ namespace ams::secmon {
using Address = u64; using Address = u64;
struct MemoryRegion { struct MemoryRegion {
private: Address start_address;
Address m_start_address; Address end_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();
}
}
constexpr Address GetStartAddress() const { constexpr MemoryRegion(Address address, size_t size) : start_address(address), end_address(address + size) {
return m_start_address; if (end_address < start_address) {
__builtin_unreachable();
} }
}
constexpr Address GetAddress() const { constexpr Address GetStartAddress() const {
return this->GetStartAddress(); return this->start_address;
} }
constexpr Address GetEndAddress() const { constexpr Address GetAddress() const {
return m_end_address; return this->GetStartAddress();
} }
constexpr Address GetLastAddress() const { constexpr Address GetEndAddress() const {
return m_end_address - 1; return this->end_address;
} }
constexpr size_t GetSize() const { constexpr Address GetLastAddress() const {
return m_end_address - m_start_address; return this->end_address - 1;
} }
constexpr bool Contains(Address address, size_t size) const { constexpr size_t GetSize() const {
return m_start_address <= address && (address + size - 1) <= this->GetLastAddress(); return this->end_address - this->start_address;
} }
constexpr bool Contains(const MemoryRegion &rhs) const { constexpr bool Contains(Address address, size_t size) const {
return this->Contains(rhs.GetStartAddress(), rhs.GetSize()); 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) constexpr bool Contains(const MemoryRegion &rhs) const {
ALWAYS_INLINE T *GetPointer() const { return this->Contains(rhs.GetStartAddress(), rhs.GetSize());
return reinterpret_cast<T *>(this->GetAddress()); }
}
template<typename T = void> requires (std::is_same<T, void>::value || util::is_pod<T>::value) template<typename T = void> requires (std::is_same<T, void>::value || util::is_pod<T>::value)
ALWAYS_INLINE T *GetEndPointer() const { ALWAYS_INLINE T *GetPointer() const {
return reinterpret_cast<T *>(this->GetEndAddress()); 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); 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 WarmbootStackAddress = MemoryRegionVirtualTzramVolatileData.GetAddress() + 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 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 Core1ExceptionStackAddress = Core0ExceptionStackAddress + CoreExceptionStackSize;
constexpr inline const Address Core2ExceptionStackAddress = Core1ExceptionStackAddress + CoreExceptionStackSize; constexpr inline const Address Core2ExceptionStackAddress = Core1ExceptionStackAddress + CoreExceptionStackSize;

View File

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

View File

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

View File

@@ -191,27 +191,27 @@ namespace ams::gic {
} }
void SetPriority(int interrupt_id, int priority) { 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) { 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) { 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) { 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) { 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) { 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() { int GetInterruptRequestId() {

View File

@@ -104,18 +104,6 @@ $(eval $(call ATMOSPHERE_ADD_TARGET, audit, $(TARGET)_audit.a, \
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \ 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 -include $(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME).mk
@@ -154,6 +142,8 @@ $(OFILES_SRC) : $(HFILES_BIN)
kern_libc_generic.o: CFLAGS += -fno-builtin 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 %_bin.h %.bin.o : %.bin
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------

View File

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

View File

@@ -248,9 +248,8 @@ namespace ams::kern::arch::arm {
return id; return id;
} }
private: 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(PriorityShift < BITSIZEOF(u8));
static_assert(util::IsPowerOfTwo(NumPriorityLevels));
static constexpr ALWAYS_INLINE u8 ToGicPriorityValue(s32 level) { static constexpr ALWAYS_INLINE u8 ToGicPriorityValue(s32 level) {
return (level << PriorityShift) | ((1 << PriorityShift) - 1); 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(alignof(KInitArguments) == util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE));
static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE))); static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)));
static_assert(AMS_OFFSETOF(KInitArguments, ttbr0) == INIT_ARGUMENTS_TTBR0); static_assert(__builtin_offsetof(KInitArguments, ttbr0) == INIT_ARGUMENTS_TTBR0);
static_assert(AMS_OFFSETOF(KInitArguments, ttbr1) == INIT_ARGUMENTS_TTBR1); static_assert(__builtin_offsetof(KInitArguments, ttbr1) == INIT_ARGUMENTS_TTBR1);
static_assert(AMS_OFFSETOF(KInitArguments, tcr) == INIT_ARGUMENTS_TCR); static_assert(__builtin_offsetof(KInitArguments, tcr) == INIT_ARGUMENTS_TCR);
static_assert(AMS_OFFSETOF(KInitArguments, mair) == INIT_ARGUMENTS_MAIR); static_assert(__builtin_offsetof(KInitArguments, mair) == INIT_ARGUMENTS_MAIR);
static_assert(AMS_OFFSETOF(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR); static_assert(__builtin_offsetof(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR);
static_assert(AMS_OFFSETOF(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR); static_assert(__builtin_offsetof(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR);
static_assert(AMS_OFFSETOF(KInitArguments, sctlr) == INIT_ARGUMENTS_SCTLR); static_assert(__builtin_offsetof(KInitArguments, sctlr) == INIT_ARGUMENTS_SCTLR);
static_assert(AMS_OFFSETOF(KInitArguments, sp) == INIT_ARGUMENTS_SP); static_assert(__builtin_offsetof(KInitArguments, sp) == INIT_ARGUMENTS_SP);
static_assert(AMS_OFFSETOF(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT); static_assert(__builtin_offsetof(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
static_assert(AMS_OFFSETOF(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT); static_assert(__builtin_offsetof(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
static_assert(AMS_OFFSETOF(KInitArguments, setup_function) == INIT_ARGUMENTS_SETUP_FUNCTION); static_assert(__builtin_offsetof(KInitArguments, setup_function) == INIT_ARGUMENTS_SETUP_FUNCTION);
static_assert(AMS_OFFSETOF(KInitArguments, exception_stack) == INIT_ARGUMENTS_EXCEPTION_STACK); 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. */ class KInitialPageTable {
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 {
public: 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: private:
KPhysicalAddress m_l1_tables[2]; KPhysicalAddress m_l1_tables[2];
u32 m_num_entries[2]; u32 m_num_entries[2];
public: public:
KInitialPageTableTemplate(KVirtualAddress start_address, KVirtualAddress end_address, PageAllocator &allocator) { KInitialPageTable(KVirtualAddress start_address, KVirtualAddress end_address, IPageAllocator &allocator) {
/* Set tables. */ /* Set tables. */
m_l1_tables[0] = AllocateNewPageTable(allocator); m_l1_tables[0] = AllocateNewPageTable(allocator);
m_l1_tables[1] = 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; m_num_entries[1] = ((end_address / L1BlockSize) & (MaxPageTableEntries - 1)) - ((start_address / L1BlockSize) & (MaxPageTableEntries - 1)) + 1;
} }
KInitialPageTableTemplate() { KInitialPageTable() {
/* Set tables. */ /* Set tables. */
m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize); m_l1_tables[0] = util::AlignDown(cpu::GetTtbr0El1(), PageSize);
m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize); m_l1_tables[1] = util::AlignDown(cpu::GetTtbr1El1(), PageSize);
@@ -98,7 +95,7 @@ namespace ams::kern::arch::arm64::init {
return l3_table + ((GetInteger(address) / L3BlockSize) & (MaxPageTableEntries - 1)); 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); auto address = allocator.Allocate(PageSize);
ClearNewPageTable(address); ClearNewPageTable(address);
return address; return address;
@@ -326,7 +323,7 @@ namespace ams::kern::arch::arm64::init {
} }
} }
public: public:
void NOINLINE Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, PageAllocator &allocator) { 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. */ /* Ensure that addresses and sizes are page aligned. */
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize));
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize)); MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize));
@@ -703,9 +700,10 @@ namespace ams::kern::arch::arm64::init {
this->PhysicallyRandomize(virt_addr, size, L3BlockSize, do_copy); this->PhysicallyRandomize(virt_addr, size, L3BlockSize, do_copy);
cpu::StoreEntireCacheForInit(); cpu::StoreEntireCacheForInit();
} }
}; };
class KInitialPageAllocator final { class KInitialPageAllocator final : public KInitialPageTable::IPageAllocator {
private: private:
static constexpr inline size_t FreeUnitSize = BITSIZEOF(u64) * PageSize; static constexpr inline size_t FreeUnitSize = BITSIZEOF(u64) * PageSize;
struct FreeListEntry { struct FreeListEntry {
@@ -809,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); 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 **prev_next = std::addressof(m_state.free_head);
auto *new_chunk = reinterpret_cast<FreeListEntry *>(GetInteger(phys_addr)); auto *new_chunk = reinterpret_cast<FreeListEntry *>(GetInteger(phys_addr));
if (auto *cur = m_state.free_head; cur != nullptr) { if (auto *cur = m_state.free_head; cur != nullptr) {
@@ -865,8 +863,5 @@ namespace ams::kern::arch::arm64::init {
*prev_next = new_chunk; *prev_next = new_chunk;
} }
}; };
static_assert(IsInitialPageAllocator<KInitialPageAllocator>);
using KInitialPageTable = KInitialPageTableTemplate<KInitialPageAllocator>;
} }

View File

@@ -30,8 +30,6 @@ namespace ams::kern::arch::arm64::cpu {
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
constexpr inline size_t NumCores = 4; constexpr inline size_t NumCores = 4;
#elif defined(ATMOSPHERE_BOARD_QEMU_VIRT)
constexpr inline size_t NumCores = 4;
#else #else
#error "Unknown Board for cpu::NumCores" #error "Unknown Board for cpu::NumCores"
#endif #endif

View File

@@ -34,9 +34,8 @@ namespace ams::kern::arch::arm64 {
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
public: public:
/* NOTE: These are virtual in Nintendo's kernel. */ virtual Result GetThreadContextImpl(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags) override;
Result GetThreadContextImpl(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags); virtual Result SetThreadContextImpl(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags) override;
Result SetThreadContextImpl(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags);
private: private:
Result GetFpuContext(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags); Result GetFpuContext(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags);
Result SetFpuContext(const ams::svc::ThreadContext &ctx, 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(sizeof(KExceptionContext) == EXCEPTION_CONTEXT_SIZE);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 0]) == EXCEPTION_CONTEXT_X0); static_assert(__builtin_offsetof(KExceptionContext, x[ 0]) == EXCEPTION_CONTEXT_X0);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 1]) == EXCEPTION_CONTEXT_X1); static_assert(__builtin_offsetof(KExceptionContext, x[ 1]) == EXCEPTION_CONTEXT_X1);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 2]) == EXCEPTION_CONTEXT_X2); static_assert(__builtin_offsetof(KExceptionContext, x[ 2]) == EXCEPTION_CONTEXT_X2);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 3]) == EXCEPTION_CONTEXT_X3); static_assert(__builtin_offsetof(KExceptionContext, x[ 3]) == EXCEPTION_CONTEXT_X3);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 4]) == EXCEPTION_CONTEXT_X4); static_assert(__builtin_offsetof(KExceptionContext, x[ 4]) == EXCEPTION_CONTEXT_X4);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 5]) == EXCEPTION_CONTEXT_X5); static_assert(__builtin_offsetof(KExceptionContext, x[ 5]) == EXCEPTION_CONTEXT_X5);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 6]) == EXCEPTION_CONTEXT_X6); static_assert(__builtin_offsetof(KExceptionContext, x[ 6]) == EXCEPTION_CONTEXT_X6);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 7]) == EXCEPTION_CONTEXT_X7); static_assert(__builtin_offsetof(KExceptionContext, x[ 7]) == EXCEPTION_CONTEXT_X7);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 8]) == EXCEPTION_CONTEXT_X8); static_assert(__builtin_offsetof(KExceptionContext, x[ 8]) == EXCEPTION_CONTEXT_X8);
static_assert(AMS_OFFSETOF(KExceptionContext, x[ 9]) == EXCEPTION_CONTEXT_X9); static_assert(__builtin_offsetof(KExceptionContext, x[ 9]) == EXCEPTION_CONTEXT_X9);
static_assert(AMS_OFFSETOF(KExceptionContext, x[10]) == EXCEPTION_CONTEXT_X10); static_assert(__builtin_offsetof(KExceptionContext, x[10]) == EXCEPTION_CONTEXT_X10);
static_assert(AMS_OFFSETOF(KExceptionContext, x[11]) == EXCEPTION_CONTEXT_X11); static_assert(__builtin_offsetof(KExceptionContext, x[11]) == EXCEPTION_CONTEXT_X11);
static_assert(AMS_OFFSETOF(KExceptionContext, x[12]) == EXCEPTION_CONTEXT_X12); static_assert(__builtin_offsetof(KExceptionContext, x[12]) == EXCEPTION_CONTEXT_X12);
static_assert(AMS_OFFSETOF(KExceptionContext, x[13]) == EXCEPTION_CONTEXT_X13); static_assert(__builtin_offsetof(KExceptionContext, x[13]) == EXCEPTION_CONTEXT_X13);
static_assert(AMS_OFFSETOF(KExceptionContext, x[14]) == EXCEPTION_CONTEXT_X14); static_assert(__builtin_offsetof(KExceptionContext, x[14]) == EXCEPTION_CONTEXT_X14);
static_assert(AMS_OFFSETOF(KExceptionContext, x[15]) == EXCEPTION_CONTEXT_X15); static_assert(__builtin_offsetof(KExceptionContext, x[15]) == EXCEPTION_CONTEXT_X15);
static_assert(AMS_OFFSETOF(KExceptionContext, x[16]) == EXCEPTION_CONTEXT_X16); static_assert(__builtin_offsetof(KExceptionContext, x[16]) == EXCEPTION_CONTEXT_X16);
static_assert(AMS_OFFSETOF(KExceptionContext, x[17]) == EXCEPTION_CONTEXT_X17); static_assert(__builtin_offsetof(KExceptionContext, x[17]) == EXCEPTION_CONTEXT_X17);
static_assert(AMS_OFFSETOF(KExceptionContext, x[18]) == EXCEPTION_CONTEXT_X18); static_assert(__builtin_offsetof(KExceptionContext, x[18]) == EXCEPTION_CONTEXT_X18);
static_assert(AMS_OFFSETOF(KExceptionContext, x[19]) == EXCEPTION_CONTEXT_X19); static_assert(__builtin_offsetof(KExceptionContext, x[19]) == EXCEPTION_CONTEXT_X19);
static_assert(AMS_OFFSETOF(KExceptionContext, x[20]) == EXCEPTION_CONTEXT_X20); static_assert(__builtin_offsetof(KExceptionContext, x[20]) == EXCEPTION_CONTEXT_X20);
static_assert(AMS_OFFSETOF(KExceptionContext, x[21]) == EXCEPTION_CONTEXT_X21); static_assert(__builtin_offsetof(KExceptionContext, x[21]) == EXCEPTION_CONTEXT_X21);
static_assert(AMS_OFFSETOF(KExceptionContext, x[22]) == EXCEPTION_CONTEXT_X22); static_assert(__builtin_offsetof(KExceptionContext, x[22]) == EXCEPTION_CONTEXT_X22);
static_assert(AMS_OFFSETOF(KExceptionContext, x[23]) == EXCEPTION_CONTEXT_X23); static_assert(__builtin_offsetof(KExceptionContext, x[23]) == EXCEPTION_CONTEXT_X23);
static_assert(AMS_OFFSETOF(KExceptionContext, x[24]) == EXCEPTION_CONTEXT_X24); static_assert(__builtin_offsetof(KExceptionContext, x[24]) == EXCEPTION_CONTEXT_X24);
static_assert(AMS_OFFSETOF(KExceptionContext, x[25]) == EXCEPTION_CONTEXT_X25); static_assert(__builtin_offsetof(KExceptionContext, x[25]) == EXCEPTION_CONTEXT_X25);
static_assert(AMS_OFFSETOF(KExceptionContext, x[26]) == EXCEPTION_CONTEXT_X26); static_assert(__builtin_offsetof(KExceptionContext, x[26]) == EXCEPTION_CONTEXT_X26);
static_assert(AMS_OFFSETOF(KExceptionContext, x[27]) == EXCEPTION_CONTEXT_X27); static_assert(__builtin_offsetof(KExceptionContext, x[27]) == EXCEPTION_CONTEXT_X27);
static_assert(AMS_OFFSETOF(KExceptionContext, x[28]) == EXCEPTION_CONTEXT_X28); static_assert(__builtin_offsetof(KExceptionContext, x[28]) == EXCEPTION_CONTEXT_X28);
static_assert(AMS_OFFSETOF(KExceptionContext, x[29]) == EXCEPTION_CONTEXT_X29); static_assert(__builtin_offsetof(KExceptionContext, x[29]) == EXCEPTION_CONTEXT_X29);
static_assert(AMS_OFFSETOF(KExceptionContext, x[30]) == EXCEPTION_CONTEXT_X30); static_assert(__builtin_offsetof(KExceptionContext, x[30]) == EXCEPTION_CONTEXT_X30);
static_assert(AMS_OFFSETOF(KExceptionContext, sp) == EXCEPTION_CONTEXT_SP); static_assert(__builtin_offsetof(KExceptionContext, sp) == EXCEPTION_CONTEXT_SP);
static_assert(AMS_OFFSETOF(KExceptionContext, pc) == EXCEPTION_CONTEXT_PC); static_assert(__builtin_offsetof(KExceptionContext, pc) == EXCEPTION_CONTEXT_PC);
static_assert(AMS_OFFSETOF(KExceptionContext, psr) == EXCEPTION_CONTEXT_PSR); static_assert(__builtin_offsetof(KExceptionContext, psr) == EXCEPTION_CONTEXT_PSR);
static_assert(AMS_OFFSETOF(KExceptionContext, tpidr) == EXCEPTION_CONTEXT_TPIDR); static_assert(__builtin_offsetof(KExceptionContext, tpidr) == EXCEPTION_CONTEXT_TPIDR);
} }

View File

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

View File

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

View File

@@ -42,7 +42,7 @@ namespace ams::kern::arch::arm64 {
const L3PageTableEntry *l3_entry; const L3PageTableEntry *l3_entry;
}; };
private: 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 NumLevels = 3;
static constexpr size_t LevelBits = 9; static constexpr size_t LevelBits = 9;
static_assert(NumLevels > 0); static_assert(NumLevels > 0);
@@ -105,9 +105,7 @@ namespace ams::kern::arch::arm64 {
return GetL3EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address); return GetL3EntryFromTable(KMemoryLayout::GetLinearVirtualAddress(entry->GetTable()), address);
} }
public: public:
constexpr explicit KPageTableImpl(util::ConstantInitializeTag) : m_table(), m_is_kernel(), m_num_entries() { /* ... */ } constexpr KPageTableImpl() : m_table(), m_is_kernel(), m_num_entries() { /* ... */ }
explicit KPageTableImpl() { /* ... */ }
NOINLINE void InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end); NOINLINE void InitializeForKernel(void *tb, KVirtualAddress start, KVirtualAddress end);
NOINLINE void InitializeForProcess(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: private:
KPageTable m_page_table; KPageTable m_page_table;
public: public:
constexpr KProcessPageTable() : m_page_table() { /* ... */ }
void Activate(u64 id) { void Activate(u64 id) {
/* Activate the page table with the specified contextidr. */ /* Activate the page table with the specified contextidr. */
m_page_table.Activate(id); m_page_table.Activate(id);

View File

@@ -25,7 +25,7 @@ namespace ams::kern::arch::arm64 {
KPageTable m_page_table; KPageTable m_page_table;
u64 m_ttbr0_identity[cpu::NumCores]; u64 m_ttbr0_identity[cpu::NumCores];
public: 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); NOINLINE void Initialize(s32 core_id);

View File

@@ -57,8 +57,7 @@ namespace ams::kern::arch::arm64 {
static void RestoreFpuRegisters64(const KThreadContext &); static void RestoreFpuRegisters64(const KThreadContext &);
static void RestoreFpuRegisters32(const KThreadContext &); static void RestoreFpuRegisters32(const KThreadContext &);
public: public:
constexpr explicit KThreadContext(util::ConstantInitializeTag) : m_callee_saved(), m_lr(), m_sp(), m_cpacr(), m_fpcr(), m_fpsr(), m_fpu_registers(), m_locked() { /* ... */ } constexpr explicit KThreadContext() : m_callee_saved(), m_lr(), m_sp(), m_cpacr(), m_fpcr(), m_fpsr(), m_fpu_registers(), m_locked() { /* ... */ }
explicit KThreadContext() { /* ... */ }
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 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(); Result Finalize();
@@ -87,25 +86,25 @@ namespace ams::kern::arch::arm64 {
consteval bool KThreadContext::ValidateOffsets() { consteval bool KThreadContext::ValidateOffsets() {
static_assert(sizeof(KThreadContext) == THREAD_CONTEXT_SIZE); static_assert(sizeof(KThreadContext) == THREAD_CONTEXT_SIZE);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.registers) == THREAD_CONTEXT_CPU_REGISTERS); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.registers) == THREAD_CONTEXT_CPU_REGISTERS);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x19) == THREAD_CONTEXT_X19); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x19) == THREAD_CONTEXT_X19);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x20) == THREAD_CONTEXT_X20); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x20) == THREAD_CONTEXT_X20);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x21) == THREAD_CONTEXT_X21); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x21) == THREAD_CONTEXT_X21);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x22) == THREAD_CONTEXT_X22); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x22) == THREAD_CONTEXT_X22);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x23) == THREAD_CONTEXT_X23); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x23) == THREAD_CONTEXT_X23);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x24) == THREAD_CONTEXT_X24); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x24) == THREAD_CONTEXT_X24);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x25) == THREAD_CONTEXT_X25); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x25) == THREAD_CONTEXT_X25);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x26) == THREAD_CONTEXT_X26); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x26) == THREAD_CONTEXT_X26);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x27) == THREAD_CONTEXT_X27); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x27) == THREAD_CONTEXT_X27);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x28) == THREAD_CONTEXT_X28); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x28) == THREAD_CONTEXT_X28);
static_assert(AMS_OFFSETOF(KThreadContext, m_callee_saved.x29) == THREAD_CONTEXT_X29); static_assert(__builtin_offsetof(KThreadContext, m_callee_saved.x29) == THREAD_CONTEXT_X29);
static_assert(AMS_OFFSETOF(KThreadContext, m_lr) == THREAD_CONTEXT_LR); static_assert(__builtin_offsetof(KThreadContext, m_lr) == THREAD_CONTEXT_LR);
static_assert(AMS_OFFSETOF(KThreadContext, m_sp) == THREAD_CONTEXT_SP); static_assert(__builtin_offsetof(KThreadContext, m_sp) == THREAD_CONTEXT_SP);
static_assert(AMS_OFFSETOF(KThreadContext, m_cpacr) == THREAD_CONTEXT_CPACR); static_assert(__builtin_offsetof(KThreadContext, m_cpacr) == THREAD_CONTEXT_CPACR);
static_assert(AMS_OFFSETOF(KThreadContext, m_fpcr) == THREAD_CONTEXT_FPCR); static_assert(__builtin_offsetof(KThreadContext, m_fpcr) == THREAD_CONTEXT_FPCR);
static_assert(AMS_OFFSETOF(KThreadContext, m_fpsr) == THREAD_CONTEXT_FPSR); static_assert(__builtin_offsetof(KThreadContext, m_fpsr) == THREAD_CONTEXT_FPSR);
static_assert(AMS_OFFSETOF(KThreadContext, m_fpu_registers) == THREAD_CONTEXT_FPU_REGISTERS); static_assert(__builtin_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_locked) == THREAD_CONTEXT_LOCKED);
return true; 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(); 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) { 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(page_table, process_address, size, device_address, device_perm, is_aligned); MESOSPHERE_UNUSED(out_mapped_size, pg, device_address, device_perm, refresh_mappings);
return ams::kern::svc::ResultNotImplemented(); return ams::kern::svc::ResultNotImplemented();
} }
Result ALWAYS_INLINE Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, KDeviceVirtualAddress device_address) { Result ALWAYS_INLINE Unmap(const KPageGroup &pg, KDeviceVirtualAddress device_address) {
MESOSPHERE_UNUSED(page_table, process_address, size, device_address); MESOSPHERE_UNUSED(pg, device_address);
return ams::kern::svc::ResultNotImplemented(); return ams::kern::svc::ResultNotImplemented();
} }

View File

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

View File

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

View File

@@ -15,17 +15,23 @@
*/ */
#pragma once #pragma once
#include <mesosphere/kern_common.hpp> #include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_system_control_base.hpp>
namespace ams::kern {
struct InitialProcessBinaryLayout;
}
namespace ams::kern::board::nintendo::nx { namespace ams::kern::board::nintendo::nx {
class KSystemControl : public KSystemControlBase { class KSystemControl {
public: public:
class Init : public KSystemControlBase::Init { class Init {
public: public:
/* Initialization. */ /* Initialization. */
static size_t GetRealMemorySize();
static size_t GetIntendedMemorySize(); static size_t GetIntendedMemorySize();
static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address);
static void GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out);
static bool ShouldIncreaseThreadResourceLimit(); static bool ShouldIncreaseThreadResourceLimit();
static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg); static void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
static size_t GetApplicationPoolSize(); static size_t GetApplicationPoolSize();
@@ -34,7 +40,7 @@ namespace ams::kern::board::nintendo::nx {
static u8 GetDebugLogUartPort(); static u8 GetDebugLogUartPort();
/* Randomness. */ /* 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 GenerateRandomRange(u64 min, u64 max);
}; };
public: public:
@@ -44,7 +50,7 @@ namespace ams::kern::board::nintendo::nx {
static NOINLINE u32 GetCreateProcessMemoryPool(); static NOINLINE u32 GetCreateProcessMemoryPool();
/* Randomness. */ /* 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 GenerateRandomRange(u64 min, u64 max);
static u64 GenerateRandomU64(); 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 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 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. */ /* Power management. */
static void SleepSystem(); static void SleepSystem();
static NORETURN void StopSystem(void *arg = nullptr); static NORETURN void StopSystem(void *arg = nullptr);
/* User access. */ /* User access. */
static void CallSecureMonitorFromUserImpl(ams::svc::lp64::SecureMonitorArguments *args); static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);
/* Secure Memory. */ /* Secure Memory. */
static size_t CalculateRequiredSecureMemorySize(size_t size, u32 pool); 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 { class Dyn {
private: private:
SXword m_tag; SXword tag;
union { union {
Xword m_value; Xword value;
Addr m_ptr; Addr ptr;
}; };
public: public:
constexpr ALWAYS_INLINE SXword GetTag() const { constexpr ALWAYS_INLINE SXword GetTag() const {
return m_tag; return this->tag;
} }
constexpr ALWAYS_INLINE Xword GetValue() const { constexpr ALWAYS_INLINE Xword GetValue() const {
return m_value; return this->value;
} }
constexpr ALWAYS_INLINE Addr GetPtr() const { constexpr ALWAYS_INLINE Addr GetPtr() const {
return m_ptr; return this->ptr;
} }
}; };
class Rel { class Rel {
private: private:
Addr m_offset; Addr offset;
Xword m_info; Xword info;
public: public:
constexpr ALWAYS_INLINE Addr GetOffset() const { constexpr ALWAYS_INLINE Addr GetOffset() const {
return m_offset; return this->offset;
} }
constexpr ALWAYS_INLINE Xword GetSym() const { constexpr ALWAYS_INLINE Xword GetSym() const {
return m_info >> 32; return this->info >> 32;
} }
constexpr ALWAYS_INLINE Xword GetType() const { constexpr ALWAYS_INLINE Xword GetType() const {
return m_info & 0xFFFFFFFF; return this->info & 0xFFFFFFFF;
} }
}; };
class Rela { class Rela {
private: private:
Addr m_offset; Addr offset;
Xword m_info; Xword info;
SXword m_addend; SXword addend;
public: public:
constexpr ALWAYS_INLINE Addr GetOffset() const { constexpr ALWAYS_INLINE Addr GetOffset() const {
return m_offset; return this->offset;
} }
constexpr ALWAYS_INLINE Xword GetSym() const { constexpr ALWAYS_INLINE Xword GetSym() const {
return m_info >> 32; return this->info >> 32;
} }
constexpr ALWAYS_INLINE Xword GetType() const { constexpr ALWAYS_INLINE Xword GetType() const {
return m_info & 0xFFFFFFFF; return this->info & 0xFFFFFFFF;
} }
constexpr ALWAYS_INLINE SXword GetAddend() const { constexpr ALWAYS_INLINE SXword GetAddend() const {
return m_addend; return this->addend;
} }
}; };

View File

@@ -32,19 +32,3 @@
//#define MESOSPHERE_BUILD_FOR_TRACING //#define MESOSPHERE_BUILD_FOR_TRACING
#define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP #define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP
#define MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP #define MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP
/* NOTE: 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 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 #ifdef ATMOSPHERE_BOARD_NINTENDO_NX
#define MESOSPHERE_DEBUG_LOG_USE_UART #define MESOSPHERE_DEBUG_LOG_USE_UART
#elif defined(ATMOSPHERE_BOARD_QEMU_VIRT)
#define MESOSPHERE_DEBUG_LOG_USE_SEMIHOSTING
#else #else
#error "Unknown board for Default Debug Log Source" #error "Unknown board for Default Debug Log Source"
#endif #endif

View File

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

View File

@@ -22,73 +22,27 @@ namespace ams::kern {
class KProcess; 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) \ #define MESOSPHERE_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
NON_COPYABLE(CLASS); \ NON_COPYABLE(CLASS); \
NON_MOVEABLE(CLASS); \ NON_MOVEABLE(CLASS); \
private: \ private: \
friend class ::ams::kern::KClassTokenGenerator; \ friend class ::ams::kern::KClassTokenGenerator; \
static constexpr inline auto ObjectType = ::ams::kern::KClassTokenGenerator::ObjectType::CLASS; \ 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>; } \ static constexpr inline ClassTokenType ClassToken() { return ::ams::kern::ClassToken<CLASS>; } \
public: \ public: \
using BaseClass = BASE_CLASS; \ using BaseClass = BASE_CLASS; \
static consteval ALWAYS_INLINE TypeObj GetStaticTypeObj() { \ static constexpr ALWAYS_INLINE TypeObj GetStaticTypeObj() { \
constexpr ClassTokenType Token = ClassToken(); \ constexpr ClassTokenType Token = ClassToken(); \
return TypeObj(TypeName, Token); \ 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 TypeObj GetTypeObj() const { return GetStaticTypeObj(); } \
virtual const char *GetTypeName() { return GetStaticTypeName(); } \ virtual const char *GetTypeName() { return GetStaticTypeName(); } \
private: private:
class KAutoObject { 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: protected:
class TypeObj { class TypeObj {
private: private:
@@ -109,61 +63,37 @@ namespace ams::kern {
} }
constexpr ALWAYS_INLINE bool IsDerivedFrom(const TypeObj &rhs) { constexpr ALWAYS_INLINE bool IsDerivedFrom(const TypeObj &rhs) {
return IsClassTokenDerivedFrom(this->GetClassToken(), rhs.GetClassToken()); return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken();
}
static constexpr ALWAYS_INLINE bool IsClassTokenDerivedFrom(ClassTokenType derived, ClassTokenType base) {
return (derived | base) == derived;
} }
}; };
private: private:
MESOSPHERE_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); MESOSPHERE_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
private: private:
KAutoObject *m_next_closed_object; KAutoObject *m_next_closed_object;
ReferenceCount m_ref_count; std::atomic<u32> m_ref_count;
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST)
ClassTokenType m_class_token;
#endif
public: public:
constexpr ALWAYS_INLINE explicit KAutoObject(util::ConstantInitializeTag) : m_next_closed_object(nullptr), m_ref_count(0) static KAutoObject *Create(KAutoObject *ptr);
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST) public:
, m_class_token(0) constexpr ALWAYS_INLINE explicit KAutoObject() : m_next_closed_object(nullptr), m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
#endif
{
MESOSPHERE_ASSERT_THIS();
}
ALWAYS_INLINE explicit KAutoObject() : m_ref_count(0) { MESOSPHERE_ASSERT_THIS(); }
/* Destroy is responsible for destroying the auto object's resources when ref_count hits zero. */ /* Destroy is responsible for destroying the auto object's resources when ref_count hits zero. */
virtual void Destroy() { MESOSPHERE_ASSERT_THIS(); } virtual void Destroy() { MESOSPHERE_ASSERT_THIS(); }
/* Finalize is responsible for cleaning up resource, but does not destroy the object. */ /* 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 */ virtual void Finalize() { MESOSPHERE_ASSERT_THIS(); }
/* is already using CRTP for slab heap, we have devirtualized it for performance gain. */
/* 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 { u32 GetReferenceCount() const {
return m_ref_count.GetValue(); return m_ref_count.load();
} }
ALWAYS_INLINE bool IsDerivedFrom(const TypeObj &rhs) const { ALWAYS_INLINE bool IsDerivedFrom(const TypeObj &rhs) const {
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST) return this->GetTypeObj().IsDerivedFrom(rhs);
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.GetClassToken());
#else
return this->GetTypeObj().IsDerivedFrom(rhs);
#endif
} }
ALWAYS_INLINE bool IsDerivedFrom(const KAutoObject &rhs) const { ALWAYS_INLINE bool IsDerivedFrom(const KAutoObject &rhs) const {
#if defined(MESOSPHERE_ENABLE_DEVIRTUALIZED_DYNAMIC_CAST) return this->IsDerivedFrom(rhs.GetTypeObj());
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.m_class_token);
#else
return this->IsDerivedFrom(rhs.GetTypeObj());
#endif
} }
template<typename Derived> template<typename Derived>
@@ -190,19 +120,8 @@ namespace ams::kern {
} }
} }
NOINLINE bool Open() { bool Open();
MESOSPHERE_ASSERT_THIS(); void Close();
return m_ref_count.Open();
}
NOINLINE void Close() {
MESOSPHERE_ASSERT_THIS();
if (m_ref_count.Close()) {
this->ScheduleDestruction();
}
}
private: private:
/* NOTE: This has to be defined *after* KThread is defined. */ /* 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. */ /* 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: public:
/* Getter, for KThread. */ /* Getter, for KThread. */
ALWAYS_INLINE KAutoObject *GetNextClosedObject() { return m_next_closed_object; } 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 { class KAutoObjectWithListContainer;
private:
void *m_alignment_forcer_unused[0];
public:
constexpr ALWAYS_INLINE explicit KAutoObjectWithListBase(util::ConstantInitializeTag) : KAutoObject(util::ConstantInitialize), m_alignment_forcer_unused{} { /* ... */ }
ALWAYS_INLINE explicit KAutoObjectWithListBase() { /* ... */ } class KAutoObjectWithList : public KAutoObject {
};
class KAutoObjectWithList : public KAutoObjectWithListBase {
private: private:
template<typename>
friend class KAutoObjectWithListContainer; friend class KAutoObjectWithListContainer;
private: private:
util::IntrusiveRedBlackTreeNode m_list_node; util::IntrusiveRedBlackTreeNode m_list_node;
public: public:
constexpr ALWAYS_INLINE KAutoObjectWithList(util::ConstantInitializeTag) : KAutoObjectWithListBase(util::ConstantInitialize), m_list_node(util::ConstantInitialize) { /* ... */ } constexpr ALWAYS_INLINE KAutoObjectWithList() : m_list_node() { /* ... */ }
ALWAYS_INLINE explicit KAutoObjectWithList() { /* ... */ }
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: public:
/* NOTE: This is virtual in Nintendo's kernel. */ virtual u64 GetId() const {
u64 GetId() const; return reinterpret_cast<u64>(this);
}
}; };
template<typename T> requires std::derived_from<T, KAutoObject> template<typename T> requires std::derived_from<T, KAutoObject>
@@ -266,6 +173,7 @@ namespace ams::kern {
std::swap(m_obj, rhs.m_obj); std::swap(m_obj, rhs.m_obj);
} }
public: public:
constexpr ALWAYS_INLINE KScopedAutoObject() : m_obj(nullptr) { /* ... */ }
constexpr ALWAYS_INLINE KScopedAutoObject(T *o) : m_obj(o) { constexpr ALWAYS_INLINE KScopedAutoObject(T *o) : m_obj(o) {
if (m_obj != nullptr) { if (m_obj != nullptr) {
m_obj->Open(); m_obj->Open();
@@ -320,52 +228,5 @@ namespace ams::kern {
constexpr ALWAYS_INLINE bool IsNotNull() const { return m_obj != nullptr; } 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 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> typename ListType::iterator begin() const {
struct GetAutoObjectWithListComparator; return m_list.begin();
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;
}
} }
return count; typename ListType::iterator end() const {
} return m_list.end();
}; }
struct DummyKAutoObjectWithListComparator { typename ListType::iterator find(typename ListType::const_reference ref) const {
static NOINLINE int Compare(KAutoObjectWithList &lhs, KAutoObjectWithList &rhs) { return m_list.find(ref);
MESOSPHERE_UNUSED(lhs, rhs); }
MESOSPHERE_PANIC("DummyKAutoObjectWithListComparator invoked"); };
}
};
}
template<typename T>
class KAutoObjectWithListContainer : public impl::KAutoObjectWithListContainerBase {
private:
using Base = impl::KAutoObjectWithListContainerBase;
public:
class ListAccessor;
friend class ListAccessor; friend class ListAccessor;
template<typename Comparator>
using ListType = util::IntrusiveRedBlackTreeMemberTraits<&KAutoObjectWithList::m_list_node>::TreeType<Comparator>;
using DummyListType = ListType<impl::DummyKAutoObjectWithListComparator>;
private: private:
DummyListType m_dummy_object_list; KLightLock m_lock;
ListType m_object_list;
public: 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(); } void Initialize() { MESOSPHERE_ASSERT_THIS(); }
ALWAYS_INLINE void Finalize() { return this->FinalizeImpl(); } void Finalize() { MESOSPHERE_ASSERT_THIS(); }
void Register(T *obj); void Register(KAutoObjectWithList *obj);
void Unregister(T *obj); void Unregister(KAutoObjectWithList *obj);
size_t GetOwnedCount(KProcess *owner);
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);
}
}; };

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; 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> template<size_t Index, size_t Count, typename T = u32>
using Field = util::BitPack32::Field<Index, Count, T>; using Field = util::BitPack32::Field<Index, Count, T>;
#define DEFINE_FIELD(name, prev, ...) using name = Field<prev::Next, __VA_ARGS__> #define DEFINE_FIELD(name, prev, ...) using name = Field<prev::Next, __VA_ARGS__>
template<CapabilityType Type> 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> 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 { struct CorePriority {
using IdBits = Field<0, CapabilityId<CapabilityType::CorePriority> + 1>; using IdBits = Field<0, CapabilityId<CapabilityType::CorePriority> + 1>;
@@ -82,11 +114,7 @@ namespace ams::kern {
DEFINE_FIELD(Index, Mask, 3); 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; static constexpr u64 PhysicalMapAllowedMask = (1ul << 36) - 1;
#endif
struct MapRange { struct MapRange {
using IdBits = Field<0, CapabilityId<CapabilityType::MapRange> + 1>; using IdBits = Field<0, CapabilityId<CapabilityType::MapRange> + 1>;
@@ -98,15 +126,9 @@ namespace ams::kern {
struct MapRangeSize { struct MapRangeSize {
using IdBits = Field<0, CapabilityId<CapabilityType::MapRange> + 1>; using IdBits = Field<0, CapabilityId<CapabilityType::MapRange> + 1>;
DEFINE_FIELD(Pages, IdBits, 20); 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(Reserved, Pages, 4); DEFINE_FIELD(Reserved, Pages, 4);
DEFINE_FIELD(Normal, Reserved, 1, bool); DEFINE_FIELD(Normal, Reserved, 1, bool);
#endif
}; };
struct MapIoPage { struct MapIoPage {
@@ -181,14 +203,14 @@ namespace ams::kern {
CapabilityFlag<CapabilityType::HandleTable> | CapabilityFlag<CapabilityType::HandleTable> |
CapabilityFlag<CapabilityType::DebugFlags>; CapabilityFlag<CapabilityType::DebugFlags>;
private: private:
svc::SvcAccessFlagSet m_svc_access_flags; svc::SvcAccessFlagSet m_svc_access_flags{};
InterruptFlagSet m_irq_access_flags; InterruptFlagSet m_irq_access_flags{};
u64 m_core_mask; u64 m_core_mask{};
u64 m_priority_mask; u64 m_priority_mask{};
util::BitPack32 m_debug_capabilities; util::BitPack32 m_debug_capabilities{0};
s32 m_handle_table_size; s32 m_handle_table_size{};
util::BitPack32 m_intended_kernel_version; util::BitPack32 m_intended_kernel_version{0};
u32 m_program_type; u32 m_program_type{};
private: private:
constexpr bool SetSvcAllowed(u32 id) { constexpr bool SetSvcAllowed(u32 id) {
if (AMS_LIKELY(id < m_svc_access_flags.GetCount())) { 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(const u32 *caps, s32 num_caps, KProcessPageTable *page_table);
Result SetCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table); Result SetCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table);
public: 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{} { /* ... */ } constexpr KCapabilities() = default;
KCapabilities() { /* ... */ }
Result Initialize(const u32 *caps, s32 num_caps, KProcessPageTable *page_table); 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); 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; 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 { class KClassTokenGenerator {
public: public:
using TokenBaseType = u16; using TokenBaseType = u16;
@@ -142,11 +113,8 @@ namespace ams::kern {
KIoPool, KIoPool,
KIoRegion, KIoRegion,
FinalClassesLast,
FinalClassesEnd = FinalClassesStart + NumFinalClasses, FinalClassesEnd = FinalClassesStart + NumFinalClasses,
}; };
static_assert(ObjectType::FinalClassesLast <= ObjectType::FinalClassesEnd);
template<typename T> template<typename T>
static constexpr inline TokenBaseType ClassToken = GetClassToken<T>(); static constexpr inline TokenBaseType ClassToken = GetClassToken<T>();
@@ -157,37 +125,4 @@ namespace ams::kern {
template<typename T> template<typename T>
static constexpr inline ClassTokenType ClassToken = KClassTokenGenerator::ClassToken<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 { class KClientPort final : public KSynchronizationObject {
MESOSPHERE_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); MESOSPHERE_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
private: private:
util::Atomic<s32> m_num_sessions; std::atomic<s32> m_num_sessions;
util::Atomic<s32> m_peak_sessions; std::atomic<s32> m_peak_sessions;
s32 m_max_sessions; s32 m_max_sessions;
KPort *m_parent; KPort *m_parent;
public: public:
constexpr explicit KClientPort(util::ConstantInitializeTag) : KSynchronizationObject(util::ConstantInitialize), m_num_sessions(0), m_peak_sessions(0), m_max_sessions(), m_parent() { /* ... */ } constexpr KClientPort() : m_num_sessions(), m_peak_sessions(), m_max_sessions(), m_parent() { /* ... */ }
explicit KClientPort() { /* ... */ }
void Initialize(KPort *parent, s32 max_sessions); void Initialize(KPort *parent, s32 max_sessions);
void OnSessionFinalized(); void OnSessionFinalized();
@@ -43,8 +41,8 @@ namespace ams::kern {
constexpr const KPort *GetParent() const { return m_parent; } constexpr const KPort *GetParent() const { return m_parent; }
ALWAYS_INLINE s32 GetNumSessions() const { return m_num_sessions.Load(); } ALWAYS_INLINE s32 GetNumSessions() const { return m_num_sessions; }
ALWAYS_INLINE s32 GetPeakSessions() const { return m_peak_sessions.Load(); } ALWAYS_INLINE s32 GetPeakSessions() const { return m_peak_sessions; }
ALWAYS_INLINE s32 GetMaxSessions() const { return m_max_sessions; } ALWAYS_INLINE s32 GetMaxSessions() const { return m_max_sessions; }
bool IsLight() const; bool IsLight() const;

View File

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

View File

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

View File

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

View File

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

View File

@@ -30,12 +30,12 @@ namespace ams::kern {
u64 m_space_size; u64 m_space_size;
bool m_is_initialized; bool m_is_initialized;
public: 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); 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); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
Result Attach(ams::svc::DeviceName device_name); Result Attach(ams::svc::DeviceName device_name);

View File

@@ -40,7 +40,7 @@ namespace ams::kern {
KVirtualAddress m_address; KVirtualAddress m_address;
size_t m_size; size_t m_size;
public: 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) { Result Initialize(KVirtualAddress memory, size_t sz) {
/* We need to have positive size. */ /* We need to have positive size. */

View File

@@ -29,19 +29,19 @@ namespace ams::kern {
private: private:
using PageBuffer = KDynamicPageManager::PageBuffer; using PageBuffer = KDynamicPageManager::PageBuffer;
private: private:
util::Atomic<size_t> m_used{0}; std::atomic<size_t> m_used{};
util::Atomic<size_t> m_peak{0}; std::atomic<size_t> m_peak{};
util::Atomic<size_t> m_count{0}; std::atomic<size_t> m_count{};
KVirtualAddress m_address{Null<KVirtualAddress>}; KVirtualAddress m_address{};
size_t m_size{}; size_t m_size{};
public: public:
constexpr KDynamicSlabHeap() = default; constexpr KDynamicSlabHeap() = default;
constexpr ALWAYS_INLINE KVirtualAddress GetAddress() const { return m_address; } constexpr ALWAYS_INLINE KVirtualAddress GetAddress() const { return m_address; }
constexpr ALWAYS_INLINE size_t GetSize() const { return m_size; } 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 GetUsed() const { return m_used.load(); }
constexpr ALWAYS_INLINE size_t GetPeak() const { return m_peak.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 GetCount() const { return m_count.load(); }
constexpr ALWAYS_INLINE bool IsInRange(KVirtualAddress addr) const { constexpr ALWAYS_INLINE bool IsInRange(KVirtualAddress addr) const {
return this->GetAddress() <= addr && addr <= this->GetAddress() + this->GetSize() - 1; return this->GetAddress() <= addr && addr <= this->GetAddress() + this->GetSize() - 1;
@@ -58,7 +58,7 @@ namespace ams::kern {
KSlabHeapImpl::Initialize(); KSlabHeapImpl::Initialize();
/* Allocate until we have the correct number of objects. */ /* 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()); auto *allocated = reinterpret_cast<T *>(page_allocator->Allocate());
MESOSPHERE_ABORT_UNLESS(allocated != nullptr); MESOSPHERE_ABORT_UNLESS(allocated != nullptr);
@@ -66,7 +66,7 @@ namespace ams::kern {
KSlabHeapImpl::Free(allocated + i); 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++) { for (size_t i = 1; i < sizeof(PageBuffer) / sizeof(T); i++) {
KSlabHeapImpl::Free(allocated + 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); std::construct_at(allocated);
/* Update our tracking. */ /* Update our tracking. */
const size_t used = ++m_used; size_t used = m_used.fetch_add(1) + 1;
size_t peak = m_peak.Load(); size_t peak = m_peak.load();
while (peak < used) { 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; break;
} }
} }
@@ -113,7 +113,7 @@ namespace ams::kern {
ALWAYS_INLINE void Free(T *t) { ALWAYS_INLINE void Free(T *t) {
KSlabHeapImpl::Free(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_initialized;
bool m_readable_event_destroyed; bool m_readable_event_destroyed;
public: public:
constexpr explicit KEvent(util::ConstantInitializeTag) constexpr KEvent()
: KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList, true>(util::ConstantInitialize), : m_readable_event(), m_owner(), m_initialized(), m_readable_event_destroyed()
m_readable_event(util::ConstantInitialize), m_owner(), m_initialized(), m_readable_event_destroyed()
{ {
/* ... */ /* ... */
} }
explicit KEvent() : m_readable_event(), m_owner(), m_initialized(), m_readable_event_destroyed() { /* ... */ }
void Initialize(); void Initialize();
void Finalize(); virtual void Finalize() override;
bool IsInitialized() const { return m_initialized; } virtual bool IsInitialized() const override { return m_initialized; }
uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_owner); } virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(m_owner); }
static void PostDestroy(uintptr_t arg); 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; } KReadableEvent &GetReadableEvent() { return m_readable_event; }

View File

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

View File

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

View File

@@ -33,14 +33,14 @@ namespace ams::kern {
public: public:
static bool IsValidIoPoolType(ams::svc::IoPoolType pool_type); static bool IsValidIoPoolType(ams::svc::IoPoolType pool_type);
public: 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); 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); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
Result AddIoRegion(KIoRegion *region); Result AddIoRegion(KIoRegion *region);

View File

@@ -40,12 +40,16 @@ namespace ams::kern {
util::IntrusiveListNode m_process_list_node; util::IntrusiveListNode m_process_list_node;
util::IntrusiveListNode m_pool_list_node; util::IntrusiveListNode m_pool_list_node;
public: 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); 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); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm); Result Map(KProcessAddress address, size_t size, ams::svc::MemoryPermission map_perm);

View File

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

View File

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

View File

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

View File

@@ -32,7 +32,7 @@ namespace ams::kern {
u64 m_server_thread_id; u64 m_server_thread_id;
KThread *m_server_thread; KThread *m_server_thread;
public: 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) { void Initialize(KLightSession *parent) {
/* Set member variables. */ /* Set member variables. */
@@ -40,6 +40,7 @@ namespace ams::kern {
} }
virtual void Destroy() override; virtual void Destroy() override;
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
constexpr const KLightSession *GetParent() const { return m_parent; } constexpr const KLightSession *GetParent() const { return m_parent; }

View File

@@ -46,13 +46,17 @@ namespace ams::kern {
KProcess *m_process; KProcess *m_process;
bool m_initialized; bool m_initialized;
public: public:
explicit KLightSession() : m_state(State::Invalid), m_process(), m_initialized() { /* ... */ } constexpr KLightSession()
: m_server(), m_client(), m_state(State::Invalid), m_port(), m_name(), m_process(), m_initialized()
{
/* ... */
}
void Initialize(KClientPort *client_port, uintptr_t name); void Initialize(KClientPort *client_port, uintptr_t name);
void Finalize(); virtual void Finalize() override;
bool IsInitialized() const { return m_initialized; } virtual bool IsInitialized() const override { return m_initialized; }
uintptr_t GetPostDestroyArgument() const { return reinterpret_cast<uintptr_t>(m_process); } virtual uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(m_process); }
static void PostDestroy(uintptr_t arg); static void PostDestroy(uintptr_t arg);

View File

@@ -349,30 +349,28 @@ namespace ams::kern {
}; };
} }
public: public:
explicit KMemoryBlock() { /* ... */ } constexpr KMemoryBlock()
: m_device_disable_merge_left_count(), m_device_disable_merge_right_count(), m_address(), m_num_pages(), m_memory_state(KMemoryState_None), m_ipc_lock_count(), m_device_use_count(), m_ipc_disable_merge_count(), m_permission(), m_original_permission(), m_attribute(), m_disable_merge_attribute()
{
/* ... */
}
constexpr KMemoryBlock(util::ConstantInitializeTag, KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) constexpr KMemoryBlock(KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr)
: util::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(util::ConstantInitialize), m_device_disable_merge_left_count(), : m_device_disable_merge_left_count(), m_device_disable_merge_right_count(), m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0), m_device_use_count(0), m_ipc_disable_merge_count(), m_permission(p), m_original_permission(KMemoryPermission_None), m_attribute(attr), m_disable_merge_attribute()
m_device_disable_merge_right_count(), m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0),
m_device_use_count(0), m_ipc_disable_merge_count(), m_permission(p), m_original_permission(KMemoryPermission_None),
m_attribute(attr), m_disable_merge_attribute()
{ {
/* ... */ /* ... */
} }
constexpr void Initialize(KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) { constexpr void Initialize(KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
m_device_disable_merge_left_count = 0; m_address = addr;
m_device_disable_merge_right_count = 0; m_num_pages = np;
m_address = addr; m_memory_state = ms;
m_num_pages = np; m_ipc_lock_count = 0;
m_memory_state = ms; m_device_use_count = 0;
m_ipc_lock_count = 0; m_permission = p;
m_device_use_count = 0; m_original_permission = KMemoryPermission_None;
m_permission = p; m_attribute = attr;
m_original_permission = KMemoryPermission_None;
m_attribute = attr;
m_disable_merge_attribute = KMemoryBlockDisableMergeAttribute_None;
} }
constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const { constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const {

View File

@@ -88,9 +88,7 @@ namespace ams::kern {
private: private:
void CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages); void CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages);
public: public:
constexpr explicit KMemoryBlockManager(util::ConstantInitializeTag) : m_memory_block_tree(), m_start_address(Null<KProcessAddress>), m_end_address(Null<KProcessAddress>) { /* ... */ } constexpr KMemoryBlockManager() : m_memory_block_tree(), m_start_address(), m_end_address() { /* ... */ }
explicit KMemoryBlockManager() { /* ... */ }
iterator end() { return m_memory_block_tree.end(); } iterator end() { return m_memory_block_tree.end(); }
const_iterator end() const { return m_memory_block_tree.end(); } const_iterator end() const { return m_memory_block_tree.end(); }
@@ -107,7 +105,7 @@ namespace ams::kern {
void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr); void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr);
iterator FindIterator(KProcessAddress address) const { iterator FindIterator(KProcessAddress address) const {
return m_memory_block_tree.find(KMemoryBlock(util::ConstantInitialize, address, 1, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None)); return m_memory_block_tree.find(KMemoryBlock(address, 1, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None));
} }
const KMemoryBlock *FindBlock(KProcessAddress address) const { const KMemoryBlock *FindBlock(KProcessAddress address) const {

View File

@@ -20,8 +20,6 @@
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) #if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
#include <mesosphere/board/nintendo/nx/kern_k_memory_layout.hpp> #include <mesosphere/board/nintendo/nx/kern_k_memory_layout.hpp>
#elif defined(ATMOSPHERE_BOARD_QEMU_VIRT)
#include <mesosphere/board/qemu/virt/kern_k_memory_layout.hpp>
#else #else
#error "Unknown board for KMemoryLayout" #error "Unknown board for KMemoryLayout"
#endif #endif
@@ -56,12 +54,12 @@ namespace ams::kern {
class KMemoryLayout { class KMemoryLayout {
private: private:
static constinit inline uintptr_t s_linear_phys_to_virt_diff; static /* constinit */ inline uintptr_t s_linear_phys_to_virt_diff;
static constinit inline uintptr_t s_linear_virt_to_phys_diff; static /* constinit */ inline uintptr_t s_linear_virt_to_phys_diff;
static constinit inline KMemoryRegionTree s_virtual_tree; static /* constinit */ inline KMemoryRegionTree s_virtual_tree;
static constinit inline KMemoryRegionTree s_physical_tree; static /* constinit */ inline KMemoryRegionTree s_physical_tree;
static constinit inline KMemoryRegionTree s_virtual_linear_tree; static /* constinit */ inline KMemoryRegionTree s_virtual_linear_tree;
static constinit inline KMemoryRegionTree s_physical_linear_tree; static /* constinit */ inline KMemoryRegionTree s_physical_linear_tree;
private: private:
template<typename AddressType> requires IsKTypedAddress<AddressType> template<typename AddressType> requires IsKTypedAddress<AddressType>
static ALWAYS_INLINE bool IsTypedAddress(const KMemoryRegion *&region, AddressType address, KMemoryRegionTree &tree, KMemoryRegionType type) { static ALWAYS_INLINE bool IsTypedAddress(const KMemoryRegion *&region, AddressType address, KMemoryRegionTree &tree, KMemoryRegionType type) {
@@ -212,17 +210,13 @@ namespace ams::kern {
static NOINLINE auto GetKernelPageTableHeapRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelPtHeap); } static NOINLINE auto GetKernelPageTableHeapRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelPtHeap); }
static NOINLINE auto GetKernelInitPageTableRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelInitPt); } static NOINLINE auto GetKernelInitPageTableRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramKernelInitPt); }
static NOINLINE auto GetKernelPoolPartitionRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramPoolPartition); }
static NOINLINE auto GetKernelPoolManagementRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramPoolManagement); } static NOINLINE auto GetKernelPoolManagementRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramPoolManagement); }
static NOINLINE auto GetKernelPoolPartitionRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramPoolPartition); }
static NOINLINE auto GetKernelSystemPoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramSystemPool); } static NOINLINE auto GetKernelSystemPoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramSystemPool); }
static NOINLINE auto GetKernelSystemNonSecurePoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramSystemNonSecurePool); } static NOINLINE auto GetKernelSystemNonSecurePoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramSystemNonSecurePool); }
static NOINLINE auto GetKernelAppletPoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramAppletPool); } static NOINLINE auto GetKernelAppletPoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramAppletPool); }
static NOINLINE auto GetKernelApplicationPoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramApplicationPool); } static NOINLINE auto GetKernelApplicationPoolRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_DramApplicationPool); }
static NOINLINE bool HasKernelSystemNonSecurePoolRegion() { return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DramSystemNonSecurePool) != nullptr; }
static NOINLINE bool HasKernelAppletPoolRegion() { return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DramAppletPool) != nullptr; }
static NOINLINE bool HasKernelApplicationPoolRegion() { return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DramApplicationPool) != nullptr; }
static NOINLINE auto GetKernelTraceBufferRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelTraceBuffer); } static NOINLINE auto GetKernelTraceBufferRegionPhysicalExtents() { return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelTraceBuffer); }
}; };

View File

@@ -68,7 +68,7 @@ namespace ams::kern {
Impl *m_next; Impl *m_next;
Impl *m_prev; Impl *m_prev;
public: public:
Impl() : m_heap(), m_page_reference_counts(), m_management_region(Null<KVirtualAddress>), m_pool(), m_next(), m_prev() { /* ... */ } Impl() : m_heap(), m_page_reference_counts(), m_management_region(), m_pool(), m_next(), m_prev() { /* ... */ }
size_t Initialize(KPhysicalAddress address, size_t size, KVirtualAddress management, KVirtualAddress management_end, Pool p); size_t Initialize(KPhysicalAddress address, size_t size, KVirtualAddress management, KVirtualAddress management_end, Pool p);

View File

@@ -43,14 +43,13 @@ namespace ams::kern {
} }
} }
public: public:
constexpr ALWAYS_INLINE KMemoryRegion() : util::IntrusiveRedBlackTreeBaseNode<KMemoryRegion>(util::ConstantInitialize), m_address(0), m_pair_address(0), m_last_address(0), m_attributes(0), m_type_id(0) { /* ... */ } constexpr ALWAYS_INLINE KMemoryRegion() : m_address(0), m_pair_address(0), m_last_address(0), m_attributes(0), m_type_id(0) { /* ... */ }
constexpr ALWAYS_INLINE KMemoryRegion(uintptr_t a, size_t la, uintptr_t p, u32 r, u32 t) :
ALWAYS_INLINE KMemoryRegion(uintptr_t a, size_t la, uintptr_t p, u32 r, u32 t) :
m_address(a), m_pair_address(p), m_last_address(la), m_attributes(r), m_type_id(t) m_address(a), m_pair_address(p), m_last_address(la), m_attributes(r), m_type_id(t)
{ {
/* ... */ /* ... */
} }
ALWAYS_INLINE KMemoryRegion(uintptr_t a, size_t la, u32 r, u32 t) : KMemoryRegion(a, la, std::numeric_limits<uintptr_t>::max(), r, t) { /* ... */ } constexpr ALWAYS_INLINE KMemoryRegion(uintptr_t a, size_t la, u32 r, u32 t) : KMemoryRegion(a, la, std::numeric_limits<uintptr_t>::max(), r, t) { /* ... */ }
private: private:
constexpr ALWAYS_INLINE void Reset(uintptr_t a, uintptr_t la, uintptr_t p, u32 r, u32 t) { constexpr ALWAYS_INLINE void Reset(uintptr_t a, uintptr_t la, uintptr_t p, u32 r, u32 t) {
m_address = a; m_address = a;

View File

@@ -29,6 +29,8 @@ namespace ams::kern {
private: private:
char m_name[NameLengthMax]; char m_name[NameLengthMax];
KAutoObject *m_object; KAutoObject *m_object;
public:
constexpr KObjectName() : m_name(), m_object() { /* ... */ }
public: public:
static Result NewFromName(KAutoObject *obj, const char *name); static Result NewFromName(KAutoObject *obj, const char *name);
static Result Delete(KAutoObject *obj, const char *name); static Result Delete(KAutoObject *obj, const char *name);

View File

@@ -43,25 +43,44 @@ namespace ams::kern {
return rnd_bit; return rnd_bit;
} }
public: public:
RandomBitGenerator() : m_entropy(), m_bits_available() { RandomBitGenerator() : m_rng(), m_entropy(), m_bits_available() {
m_rng.Initialize(static_cast<u32>(KSystemControl::GenerateRandomU64())); m_rng.Initialize(static_cast<u32>(KSystemControl::GenerateRandomU64()));
} }
size_t SelectRandomBit(u64 bitmap) { size_t SelectRandomBit(u64 bitmap) {
u64 selected = 0; u64 selected = 0;
for (size_t cur_num_bits = BITSIZEOF(bitmap) / 2; cur_num_bits != 0; cur_num_bits /= 2) { u64 cur_num_bits = BITSIZEOF(bitmap) / 2;
const u64 high = (bitmap >> cur_num_bits); u64 cur_mask = (1ull << cur_num_bits) - 1;
const u64 low = (bitmap & (~(UINT64_C(0xFFFFFFFFFFFFFFFF) << cur_num_bits)));
/* Choose high if we have high and (don't have low or select high randomly). */ while (cur_num_bits) {
if (high && (low == 0 || this->GenerateRandomBit())) { const u64 low = (bitmap >> 0) & cur_mask;
bitmap = high; const u64 high = (bitmap >> cur_num_bits) & cur_mask;
selected += cur_num_bits;
bool choose_low;
if (high == 0) {
/* If only low val is set, choose low. */
choose_low = true;
} else if (low == 0) {
/* If only high val is set, choose high. */
choose_low = false;
} else { } else {
/* If both are set, choose random. */
choose_low = this->GenerateRandomBit();
}
/* If we chose low, proceed with low. */
if (choose_low) {
bitmap = low; bitmap = low;
selected += 0; selected += 0;
} else {
bitmap = high;
selected += cur_num_bits;
} }
/* Proceed. */
cur_num_bits /= 2;
cur_mask >>= cur_num_bits;
} }
return selected; return selected;

View File

@@ -28,11 +28,11 @@ namespace ams::kern {
private: private:
friend class KPageGroup; friend class KPageGroup;
private: private:
KBlockInfo *m_next; KBlockInfo *m_next{};
u32 m_page_index; u32 m_page_index{};
u32 m_num_pages; u32 m_num_pages{};
public: public:
KBlockInfo() : m_next(nullptr) { /* ... */ } constexpr KBlockInfo() = default;
constexpr ALWAYS_INLINE void Initialize(KPhysicalAddress addr, size_t np) { constexpr ALWAYS_INLINE void Initialize(KPhysicalAddress addr, size_t np) {
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), PageSize)); MESOSPHERE_ASSERT(util::IsAligned(GetInteger(addr), PageSize));

View File

@@ -59,7 +59,7 @@ namespace ams::kern {
size_t m_block_shift; size_t m_block_shift;
size_t m_next_block_shift; size_t m_next_block_shift;
public: public:
Block() : m_bitmap(), m_heap_address(Null<KPhysicalAddress>), m_end_offset(), m_block_shift(), m_next_block_shift() { /* ... */ } Block() : m_bitmap(), m_heap_address(), m_end_offset(), m_block_shift(), m_next_block_shift() { /* ... */ }
constexpr size_t GetShift() const { return m_block_shift; } constexpr size_t GetShift() const { return m_block_shift; }
constexpr size_t GetNextShift() const { return m_next_block_shift; } constexpr size_t GetNextShift() const { return m_next_block_shift; }
@@ -134,7 +134,7 @@ namespace ams::kern {
void FreeBlock(KPhysicalAddress block, s32 index); void FreeBlock(KPhysicalAddress block, s32 index);
public: public:
KPageHeap() : m_heap_address(Null<KPhysicalAddress>), m_heap_size(), m_initial_used_size(), m_num_blocks(), m_blocks() { /* ... */ } KPageHeap() : m_heap_address(), m_heap_size(), m_initial_used_size(), m_num_blocks(), m_blocks() { /* ... */ }
constexpr KPhysicalAddress GetAddress() const { return m_heap_address; } constexpr KPhysicalAddress GetAddress() const { return m_heap_address; }
constexpr size_t GetSize() const { return m_heap_size; } constexpr size_t GetSize() const { return m_heap_size; }

View File

@@ -144,60 +144,45 @@ namespace ams::kern {
PageLinkedList *GetPageList() { return std::addressof(m_ll); } PageLinkedList *GetPageList() { return std::addressof(m_ll); }
}; };
private: private:
KProcessAddress m_address_space_start; KProcessAddress m_address_space_start{};
KProcessAddress m_address_space_end; KProcessAddress m_address_space_end{};
KProcessAddress m_heap_region_start; KProcessAddress m_heap_region_start{};
KProcessAddress m_heap_region_end; KProcessAddress m_heap_region_end{};
KProcessAddress m_current_heap_end; KProcessAddress m_current_heap_end{};
KProcessAddress m_alias_region_start; KProcessAddress m_alias_region_start{};
KProcessAddress m_alias_region_end; KProcessAddress m_alias_region_end{};
KProcessAddress m_stack_region_start; KProcessAddress m_stack_region_start{};
KProcessAddress m_stack_region_end; KProcessAddress m_stack_region_end{};
KProcessAddress m_kernel_map_region_start; KProcessAddress m_kernel_map_region_start{};
KProcessAddress m_kernel_map_region_end; KProcessAddress m_kernel_map_region_end{};
KProcessAddress m_alias_code_region_start; KProcessAddress m_alias_code_region_start{};
KProcessAddress m_alias_code_region_end; KProcessAddress m_alias_code_region_end{};
KProcessAddress m_code_region_start; KProcessAddress m_code_region_start{};
KProcessAddress m_code_region_end; KProcessAddress m_code_region_end{};
size_t m_max_heap_size; size_t m_max_heap_size{};
size_t m_mapped_physical_memory_size; size_t m_mapped_physical_memory_size{};
size_t m_mapped_unsafe_physical_memory; size_t m_mapped_unsafe_physical_memory{};
size_t m_mapped_ipc_server_memory; size_t m_mapped_ipc_server_memory{};
mutable KLightLock m_general_lock; mutable KLightLock m_general_lock{};
mutable KLightLock m_map_physical_memory_lock; mutable KLightLock m_map_physical_memory_lock{};
KLightLock m_device_map_lock; KLightLock m_device_map_lock{};
KPageTableImpl m_impl; KPageTableImpl m_impl{};
KMemoryBlockManager m_memory_block_manager; KMemoryBlockManager m_memory_block_manager{};
u32 m_allocate_option; u32 m_allocate_option{};
u32 m_address_space_width; u32 m_address_space_width{};
bool m_is_kernel; bool m_is_kernel{};
bool m_enable_aslr; bool m_enable_aslr{};
bool m_enable_device_address_space_merge; bool m_enable_device_address_space_merge{};
KMemoryBlockSlabManager *m_memory_block_slab_manager; KMemoryBlockSlabManager *m_memory_block_slab_manager{};
KBlockInfoManager *m_block_info_manager; KBlockInfoManager *m_block_info_manager{};
KResourceLimit *m_resource_limit; KResourceLimit *m_resource_limit{};
const KMemoryRegion *m_cached_physical_linear_region; const KMemoryRegion *m_cached_physical_linear_region{};
const KMemoryRegion *m_cached_physical_heap_region; const KMemoryRegion *m_cached_physical_heap_region{};
MemoryFillValue m_heap_fill_value; MemoryFillValue m_heap_fill_value{};
MemoryFillValue m_ipc_fill_value; MemoryFillValue m_ipc_fill_value{};
MemoryFillValue m_stack_fill_value; MemoryFillValue m_stack_fill_value{};
public: public:
constexpr explicit KPageTableBase(util::ConstantInitializeTag) constexpr KPageTableBase() { /* ... */ }
: m_address_space_start(Null<KProcessAddress>), m_address_space_end(Null<KProcessAddress>), m_heap_region_start(Null<KProcessAddress>),
m_heap_region_end(Null<KProcessAddress>), m_current_heap_end(Null<KProcessAddress>), m_alias_region_start(Null<KProcessAddress>),
m_alias_region_end(Null<KProcessAddress>), m_stack_region_start(Null<KProcessAddress>), m_stack_region_end(Null<KProcessAddress>),
m_kernel_map_region_start(Null<KProcessAddress>), m_kernel_map_region_end(Null<KProcessAddress>), m_alias_code_region_start(Null<KProcessAddress>),
m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>),
m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_ipc_server_memory(), m_general_lock(),
m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(),
m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(),
m_heap_fill_value(), m_ipc_fill_value(), m_stack_fill_value()
{
/* ... */
}
explicit KPageTableBase() { /* ... */ }
NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end); NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end);
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KResourceLimit *resource_limit); NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KResourceLimit *resource_limit);

View File

@@ -27,10 +27,9 @@ namespace ams::kern {
private: private:
using BaseHeap = KDynamicResourceManager<impl::PageTablePage, true>; using BaseHeap = KDynamicResourceManager<impl::PageTablePage, true>;
private: private:
KPageTableSlabHeap *m_pt_heap; KPageTableSlabHeap *m_pt_heap{};
public: public:
constexpr explicit KPageTableManager(util::ConstantInitializeTag) : m_pt_heap() { /* ... */ } constexpr KPageTableManager() = default;
explicit KPageTableManager() { /* ... */ }
ALWAYS_INLINE void Initialize(KDynamicPageManager *page_allocator, KPageTableSlabHeap *pt_heap) { ALWAYS_INLINE void Initialize(KDynamicPageManager *page_allocator, KPageTableSlabHeap *pt_heap) {
m_pt_heap = pt_heap; m_pt_heap = pt_heap;

View File

@@ -41,13 +41,11 @@ namespace ams::kern {
State m_state; State m_state;
bool m_is_light; bool m_is_light;
public: public:
explicit KPort() : m_state(State::Invalid), m_is_light() { /* ... */ } constexpr KPort() : m_server(), m_client(), m_name(), m_state(State::Invalid), m_is_light() { /* ... */ }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
void Initialize(s32 max_sessions, bool is_light, uintptr_t name); void Initialize(s32 max_sessions, bool is_light, uintptr_t name);
void Finalize() { /* ... */ }
void OnClientClosed(); void OnClientClosed();
void OnServerClosed(); void OnServerClosed();

View File

@@ -235,7 +235,7 @@ namespace ams::kern {
KPriorityQueueImpl m_suggested_queue; KPriorityQueueImpl m_suggested_queue;
private: private:
constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) { constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) {
affinity &= ~(UINT64_C(1) << core); affinity &= ~(u64(1ul) << core);
} }
constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) { constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) {

View File

@@ -34,7 +34,7 @@
namespace ams::kern { namespace ams::kern {
class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> { class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>, public KWorkerTask {
MESOSPHERE_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); MESOSPHERE_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
public: public:
enum State { enum State {
@@ -57,73 +57,73 @@ namespace ams::kern {
using TLPTree = util::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>; using TLPTree = util::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
using TLPIterator = TLPTree::iterator; using TLPIterator = TLPTree::iterator;
private: private:
KProcessPageTable m_page_table; KProcessPageTable m_page_table{};
util::Atomic<size_t> m_used_kernel_memory_size; std::atomic<size_t> m_used_kernel_memory_size{};
TLPTree m_fully_used_tlp_tree; TLPTree m_fully_used_tlp_tree{};
TLPTree m_partially_used_tlp_tree; TLPTree m_partially_used_tlp_tree{};
s32 m_ideal_core_id; s32 m_ideal_core_id{};
void *m_attached_object; void *m_attached_object{};
KResourceLimit *m_resource_limit; KResourceLimit *m_resource_limit{};
KVirtualAddress m_system_resource_address; KVirtualAddress m_system_resource_address{};
size_t m_system_resource_num_pages; size_t m_system_resource_num_pages{};
size_t m_memory_release_hint; size_t m_memory_release_hint{};
State m_state; State m_state{};
KLightLock m_state_lock; KLightLock m_state_lock{};
KLightLock m_list_lock; KLightLock m_list_lock{};
KConditionVariable m_cond_var; KConditionVariable m_cond_var{};
KAddressArbiter m_address_arbiter; KAddressArbiter m_address_arbiter{};
u64 m_entropy[4]; u64 m_entropy[4]{};
bool m_is_signaled; bool m_is_signaled{};
bool m_is_initialized; bool m_is_initialized{};
bool m_is_application; bool m_is_application{};
char m_name[13]; char m_name[13]{};
util::Atomic<u16> m_num_running_threads; std::atomic<u16> m_num_running_threads{};
u32 m_flags; u32 m_flags{};
KMemoryManager::Pool m_memory_pool; KMemoryManager::Pool m_memory_pool{};
s64 m_schedule_count; s64 m_schedule_count{};
KCapabilities m_capabilities; KCapabilities m_capabilities{};
ams::svc::ProgramId m_program_id; ams::svc::ProgramId m_program_id{};
u64 m_process_id; u64 m_process_id{};
s64 m_creation_time; s64 m_creation_time{};
KProcessAddress m_code_address; KProcessAddress m_code_address{};
size_t m_code_size; size_t m_code_size{};
size_t m_main_thread_stack_size; size_t m_main_thread_stack_size{};
size_t m_max_process_memory; size_t m_max_process_memory{};
u32 m_version; u32 m_version{};
KHandleTable m_handle_table; KHandleTable m_handle_table{};
KProcessAddress m_plr_address; KProcessAddress m_plr_address{};
void *m_plr_heap_address; void *m_plr_heap_address{};
KThread *m_exception_thread; KThread *m_exception_thread{};
ThreadList m_thread_list; ThreadList m_thread_list{};
SharedMemoryInfoList m_shared_memory_list; SharedMemoryInfoList m_shared_memory_list{};
IoRegionList m_io_region_list; IoRegionList m_io_region_list{};
bool m_is_suspended; bool m_is_suspended{};
bool m_is_immortal; bool m_is_immortal{};
bool m_is_jit_debug; bool m_is_jit_debug{};
bool m_is_handle_table_initialized; bool m_is_handle_table_initialized{};
ams::svc::DebugEvent m_jit_debug_event_type; ams::svc::DebugEvent m_jit_debug_event_type{};
ams::svc::DebugException m_jit_debug_exception_type; ams::svc::DebugException m_jit_debug_exception_type{};
uintptr_t m_jit_debug_params[4]; uintptr_t m_jit_debug_params[4]{};
u64 m_jit_debug_thread_id; u64 m_jit_debug_thread_id{};
KWaitObject m_wait_object; KWaitObject m_wait_object{};
KThread *m_running_threads[cpu::NumCores]; KThread *m_running_threads[cpu::NumCores]{};
u64 m_running_thread_idle_counts[cpu::NumCores]; u64 m_running_thread_idle_counts[cpu::NumCores]{};
KThread *m_pinned_threads[cpu::NumCores]; KThread *m_pinned_threads[cpu::NumCores]{};
util::Atomic<s64> m_cpu_time; std::atomic<s64> m_cpu_time{};
util::Atomic<s64> m_num_process_switches; std::atomic<s64> m_num_process_switches{};
util::Atomic<s64> m_num_thread_switches; std::atomic<s64> m_num_thread_switches{};
util::Atomic<s64> m_num_fpu_switches; std::atomic<s64> m_num_fpu_switches{};
util::Atomic<s64> m_num_supervisor_calls; std::atomic<s64> m_num_supervisor_calls{};
util::Atomic<s64> m_num_ipc_messages; std::atomic<s64> m_num_ipc_messages{};
util::Atomic<s64> m_num_ipc_replies; std::atomic<s64> m_num_ipc_replies{};
util::Atomic<s64> m_num_ipc_receives; std::atomic<s64> m_num_ipc_receives{};
KDynamicPageManager m_dynamic_page_manager; KDynamicPageManager m_dynamic_page_manager{};
KMemoryBlockSlabManager m_memory_block_slab_manager; KMemoryBlockSlabManager m_memory_block_slab_manager{};
KBlockInfoManager m_block_info_manager; KBlockInfoManager m_block_info_manager{};
KPageTableManager m_page_table_manager; KPageTableManager m_page_table_manager{};
KMemoryBlockSlabHeap m_memory_block_heap; KMemoryBlockSlabHeap m_memory_block_heap{};
KBlockInfoSlabHeap m_block_info_heap; KBlockInfoSlabHeap m_block_info_heap{};
KPageTableSlabHeap m_page_table_heap; KPageTableSlabHeap m_page_table_heap{};
private: private:
Result Initialize(const ams::svc::CreateProcessParameter &params); Result Initialize(const ams::svc::CreateProcessParameter &params);
@@ -145,7 +145,7 @@ namespace ams::kern {
m_pinned_threads[core_id] = nullptr; m_pinned_threads[core_id] = nullptr;
} }
public: public:
explicit KProcess() : m_is_initialized(false) { /* ... */ } KProcess() { /* ... */ }
Result Initialize(const ams::svc::CreateProcessParameter &params, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool, bool immortal); Result Initialize(const ams::svc::CreateProcessParameter &params, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool, bool immortal);
Result Initialize(const ams::svc::CreateProcessParameter &params, svc::KUserPointer<const u32 *> caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool); Result Initialize(const ams::svc::CreateProcessParameter &params, svc::KUserPointer<const u32 *> caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool);
@@ -284,12 +284,8 @@ namespace ams::kern {
constexpr KProcessAddress GetProcessLocalRegionAddress() const { return m_plr_address; } constexpr KProcessAddress GetProcessLocalRegionAddress() const { return m_plr_address; }
constexpr void *GetProcessLocalRegionHeapAddress() const { return m_plr_heap_address; }
KThread *GetExceptionThread() const { return m_exception_thread; }
void AddCpuTime(s64 diff) { m_cpu_time += diff; } void AddCpuTime(s64 diff) { m_cpu_time += diff; }
s64 GetCpuTime() { return m_cpu_time.Load(); } s64 GetCpuTime() { return m_cpu_time; }
constexpr s64 GetScheduledCount() const { return m_schedule_count; } constexpr s64 GetScheduledCount() const { return m_schedule_count; }
void IncrementScheduledCount() { ++m_schedule_count; } void IncrementScheduledCount() { ++m_schedule_count; }
@@ -384,14 +380,13 @@ namespace ams::kern {
} }
public: public:
/* Overridden parent functions. */ /* Overridden parent functions. */
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); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
void Finalize(); virtual void Finalize() override;
ALWAYS_INLINE u64 GetIdImpl() const { return this->GetProcessId(); } virtual u64 GetId() const override final { return this->GetProcessId(); }
ALWAYS_INLINE u64 GetId() const { return this->GetIdImpl(); }
virtual bool IsSignaled() const override { virtual bool IsSignaled() const override {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
@@ -399,7 +394,7 @@ namespace ams::kern {
return m_is_signaled; return m_is_signaled;
} }
void DoWorkerTaskImpl(); virtual void DoWorkerTask() override;
private: private:
void ChangeState(State new_state) { void ChangeState(State new_state) {
if (m_state != new_state) { if (m_state != new_state) {

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