diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp
index 20aa5eaa2..de463ce6b 100644
--- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp
+++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp
@@ -357,7 +357,12 @@ namespace ams::kern::board::nintendo::nx {
/* Return (possibly) adjusted size. */
/* NOTE: On 20.0.0+ (and even more-so 21.0.0+) the browser requires much more memory in the applet pool in order to function. */
/* Thus, we have to reduce our extra system memory size by 26 MB to compensate. */
- if (kern::GetTargetFirmware() >= ams::TargetFirmware_21_0_0) {
+ /* NOTE: On 23.0.0+ we are patching memory allocation for each browser applet since there are only 3 of them now. */
+ /* Given that the root "Reserved" region is 0x43E000 bytes and the "ReservedTbd" subregion is 0x540000 bytes, we can safely reclaim 9MB.*/
+ if (kern::GetTargetFirmware() >= ams::TargetFirmware_23_0_0) {
+ constexpr size_t ExtraSystemMemoryForAtmosphere_23_0_0 = 16_MB;
+ return base_pool_size - ExtraSystemMemoryForAtmosphere_23_0_0 - KTraceBufferSize;
+ } else if (kern::GetTargetFirmware() >= ams::TargetFirmware_21_0_0) {
constexpr size_t ExtraSystemMemoryForAtmosphere_21_0_0 = 7_MB;
return base_pool_size - ExtraSystemMemoryForAtmosphere_21_0_0 - KTraceBufferSize;
} else if (kern::GetTargetFirmware() >= ams::TargetFirmware_20_0_0) {
diff --git a/stratosphere/loader/source/ldr_embedded_web_patches.inc b/stratosphere/loader/source/ldr_embedded_web_patches.inc
new file mode 100644
index 000000000..825123005
--- /dev/null
+++ b/stratosphere/loader/source/ldr_embedded_web_patches.inc
@@ -0,0 +1,61 @@
+/*
+ * 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 .
+ */
+
+/* Breakdown of each patch in order: */
+/* #1 - Patch the 0xDEEF000 size check branch to NOP. */
+/* #2 - Change the root heap "Reserved" region allocation size from 0x43E000 to 0. */
+/* #3 - Change the root heap "Scene" size from 0x4580000 to 0x4040000. */
+/* #4 - Change the scene heap "ReservedTbd" region allocation size from 0x540000 to 0. */
+/* #5 - Patch the linking of "ReservedTbd" to the parent heap with a NOP. */
+/* #6 - Patch the initial memory block allocation size from 0xB400000 to 0xAC00000. */
+/* #7 - Patch the initial memory block initialization size from 0xB400000 to 0xAC00000. */
+constexpr inline const EmbeddedPatchEntry SystemWebMemoryPatches_23_0_0[] = {
+ { 0x861DD4, "\x1F\x20\x03\xD5", 4 },
+ { 0x861E80, "\x02\x00\x80\x52", 4 },
+ { 0x861E6C, "\x82\x80\xA0\x52", 4 },
+ { 0x8C1718, "\x02\x00\x80\x52", 4 },
+ { 0x8C172C, "\x1F\x20\x03\xD5", 4 },
+ { 0x861D44, "\x01\x58\xA1\x52", 4 },
+ { 0x861D5C, "\x03\x58\xA1\x52", 4 },
+};
+
+constexpr inline const EmbeddedPatchEntry OpenWebMemoryPatches_23_0_0[] = {
+ { 0x828DBC, "\x1F\x20\x03\xD5", 4 },
+ { 0x828E68, "\x02\x00\x80\x52", 4 },
+ { 0x828E54, "\x82\x80\xA0\x52", 4 },
+ { 0x74C564, "\x02\x00\x80\x52", 4 },
+ { 0x74C578, "\x1F\x20\x03\xD5", 4 },
+ { 0x828D2C, "\x01\x58\xA1\x52", 4 },
+ { 0x828D44, "\x03\x58\xA1\x52", 4 },
+};
+
+constexpr inline const EmbeddedPatchEntry OfflineWebMemoryPatches_23_0_0[] = {
+ { 0x130698, "\x1F\x20\x03\xD5", 4 },
+ { 0x130744, "\x02\x00\x80\x52", 4 },
+ { 0x130730, "\x82\x80\xA0\x52", 4 },
+ { 0x4D728, "\x02\x00\x80\x52", 4 },
+ { 0x4D738, "\x1F\x20\x03\xD5", 4 },
+ { 0x130614, "\x01\x58\xA1\x52", 4 },
+ { 0x130624, "\x02\x58\xA1\x52", 4 },
+};
+
+constexpr inline const EmbeddedPatch WebMemoryPatches[] = {
+ { ParseModuleId("97BF9C2D43EB002FB5B3578E7714F428104ED596"), util::size(SystemWebMemoryPatches_23_0_0), SystemWebMemoryPatches_23_0_0 }, /* 23.0.0 */
+
+ { ParseModuleId("1470453424A9CDE689BE6DA86457ED1C79F5F403"), util::size(OpenWebMemoryPatches_23_0_0), OpenWebMemoryPatches_23_0_0 }, /* 23.0.0 */
+
+ { ParseModuleId("86DAFFA68DA38660317018ADC7AD415BCCDDC583"), util::size(OfflineWebMemoryPatches_23_0_0), OfflineWebMemoryPatches_23_0_0 }, /* 23.0.0 */
+};
diff --git a/stratosphere/loader/source/ldr_patcher.cpp b/stratosphere/loader/source/ldr_patcher.cpp
index c78b3919b..a6776b691 100644
--- a/stratosphere/loader/source/ldr_patcher.cpp
+++ b/stratosphere/loader/source/ldr_patcher.cpp
@@ -109,6 +109,7 @@ namespace ams::ldr {
#include "ldr_embedded_usb_patches.inc"
#include "ldr_embedded_am_patches.inc"
+ #include "ldr_embedded_web_patches.inc"
}
@@ -153,6 +154,18 @@ namespace ams::ldr {
}
}
}
+
+ /* TODO: Remove this if/when a cleaner solution is figured out. */
+ for (const auto &patch : WebMemoryPatches) {
+ if (std::memcmp(std::addressof(patch.module_id), std::addressof(module_id), sizeof(module_id)) == 0) {
+ for (size_t i = 0; i < patch.num_entries; ++i) {
+ const auto &entry = patch.entries[i];
+ if (entry.offset + entry.size <= mapped_size) {
+ std::memcpy(reinterpret_cast(mapped_nso + entry.offset), entry.data, entry.size);
+ }
+ }
+ }
+ }
}
}
\ No newline at end of file