From d562bb841d3dfea91dca9f340f014c794ad23c32 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 22 Oct 2021 09:33:53 -0700 Subject: [PATCH] kern: add toggleable support for 40-bit physaddr caps --- .../include/mesosphere/kern_build_config.hpp | 11 ++++++++++- .../include/mesosphere/kern_k_capabilities.hpp | 12 +++++++++++- .../libmesosphere/source/kern_k_capabilities.cpp | 10 +++++++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp b/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp index 8216bab0c..cb0de2781 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_build_config.hpp @@ -38,4 +38,13 @@ /* 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 \ No newline at end of file +#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 \ No newline at end of file diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp index fd69590b8..3c31124d8 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_capabilities.hpp @@ -82,7 +82,11 @@ namespace ams::kern { DEFINE_FIELD(Index, Mask, 3); }; + #if defined(MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES) + static constexpr u64 PhysicalMapAllowedMask = (1ul << 40) - 1; + #else static constexpr u64 PhysicalMapAllowedMask = (1ul << 36) - 1; + #endif struct MapRange { using IdBits = Field<0, CapabilityId + 1>; @@ -94,9 +98,15 @@ namespace ams::kern { struct MapRangeSize { using IdBits = Field<0, CapabilityId + 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(Normal, Reserved, 1, bool); + #endif }; struct MapIoPage { diff --git a/libraries/libmesosphere/source/kern_k_capabilities.cpp b/libraries/libmesosphere/source/kern_k_capabilities.cpp index d2000e632..1aa8f4999 100644 --- a/libraries/libmesosphere/source/kern_k_capabilities.cpp +++ b/libraries/libmesosphere/source/kern_k_capabilities.cpp @@ -117,11 +117,15 @@ namespace ams::kern { } Result KCapabilities::MapRange(const util::BitPack32 cap, const util::BitPack32 size_cap, KProcessPageTable *page_table) { + /* Get/validate address/size */ + #if defined(MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES) + const u64 phys_addr = static_cast(cap.Get() | (size_cap.Get() << MapRange::Address::Count)) * PageSize; + #else + const u64 phys_addr = static_cast(cap.Get()) * PageSize; + /* Validate reserved bits are unused. */ R_UNLESS(size_cap.Get() == 0, svc::ResultOutOfRange()); - - /* Get/validate address/size */ - const u64 phys_addr = cap.Get() * PageSize; + #endif const size_t num_pages = size_cap.Get(); const size_t size = num_pages * PageSize; R_UNLESS(phys_addr == GetInteger(KPhysicalAddress(phys_addr)), svc::ResultInvalidAddress());