mirror of
				https://github.com/Atmosphere-NX/Atmosphere.git
				synced 2025-11-03 20:41:17 +01:00 
			
		
		
		
	* result: try out some experimental shenanigans * result: sketch out some more shenanigans * result: see what it looks like to convert kernel to use result conds instead of guards * make rest of kernel use experimental new macro-ing
		
			
				
	
	
		
			160 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) Atmosphère-NX
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify it
 | 
						|
 * under the terms and conditions of the GNU General Public License,
 | 
						|
 * version 2, as published by the Free Software Foundation.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope it will be useful, but WITHOUT
 | 
						|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
						|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | 
						|
 * more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
#include <mesosphere.hpp>
 | 
						|
 | 
						|
namespace ams::kern::svc {
 | 
						|
 | 
						|
    /* =============================    Common    ============================= */
 | 
						|
 | 
						|
    namespace {
 | 
						|
 | 
						|
        Result QueryPhysicalAddress(ams::svc::PhysicalMemoryInfo *out_info, uintptr_t address) {
 | 
						|
            /* NOTE: In 10.0.0, Nintendo stubbed this SVC. Should we do so? */
 | 
						|
            /* R_UNLESS(GetTargetFirmware() < TargetFirmware_10_0_0, svc::ResultInvalidCurrentMemory()); */
 | 
						|
 | 
						|
            /* Get reference to page table. */
 | 
						|
            auto &pt = GetCurrentProcess().GetPageTable();
 | 
						|
 | 
						|
            /* Check that the address is valid. */
 | 
						|
            R_UNLESS(pt.Contains(address, 1), svc::ResultInvalidCurrentMemory());
 | 
						|
 | 
						|
            /* Query the physical mapping. */
 | 
						|
            R_TRY(pt.QueryPhysicalAddress(out_info, address));
 | 
						|
 | 
						|
            R_SUCCEED();
 | 
						|
        }
 | 
						|
 | 
						|
        Result QueryIoMapping(uintptr_t *out_address, size_t *out_size, uint64_t phys_addr, size_t size) {
 | 
						|
            /* Declare variables we'll populate. */
 | 
						|
            KProcessAddress found_address = Null<KProcessAddress>;
 | 
						|
            size_t          found_size    = 0;
 | 
						|
 | 
						|
            /* Get reference to page table. */
 | 
						|
            auto &pt = GetCurrentProcess().GetPageTable();
 | 
						|
 | 
						|
            /* Check whether the address is aligned. */
 | 
						|
            const bool aligned = util::IsAligned(phys_addr, PageSize);
 | 
						|
 | 
						|
            auto QueryIoMappingFromPageTable = [&](uint64_t phys_addr, size_t size) ALWAYS_INLINE_LAMBDA -> Result {
 | 
						|
                /* The size must be non-zero. */
 | 
						|
                R_UNLESS(size > 0, svc::ResultInvalidSize());
 | 
						|
 | 
						|
                /* The request must not overflow. */
 | 
						|
                R_UNLESS((phys_addr < phys_addr + size), svc::ResultNotFound());
 | 
						|
 | 
						|
                /* Query the mapping. */
 | 
						|
                R_TRY(pt.QueryIoMapping(std::addressof(found_address), phys_addr, size));
 | 
						|
 | 
						|
                /* Use the size as the found size. */
 | 
						|
                found_size = size;
 | 
						|
 | 
						|
                R_SUCCEED();
 | 
						|
            };
 | 
						|
 | 
						|
            if (aligned) {
 | 
						|
                /* Query the input. */
 | 
						|
                R_TRY(QueryIoMappingFromPageTable(phys_addr, size));
 | 
						|
            } else {
 | 
						|
                if (kern::GetTargetFirmware() < TargetFirmware_8_0_0 && phys_addr >= PageSize) {
 | 
						|
                    /* Query the aligned-down page. */
 | 
						|
                    const size_t offset = phys_addr & (PageSize - 1);
 | 
						|
                    R_TRY(QueryIoMappingFromPageTable(phys_addr - offset, size + offset));
 | 
						|
 | 
						|
                    /* Adjust the output address. */
 | 
						|
                    found_address += offset;
 | 
						|
                } else {
 | 
						|
                    /* Newer kernel only allows unaligned addresses when they're special enum members. */
 | 
						|
                    R_UNLESS(phys_addr < PageSize, svc::ResultNotFound());
 | 
						|
 | 
						|
                    /* Try to find the memory region. */
 | 
						|
                    const KMemoryRegion * const region = [] ALWAYS_INLINE_LAMBDA (ams::svc::MemoryRegionType type) -> const KMemoryRegion * {
 | 
						|
                        switch (type) {
 | 
						|
                            case ams::svc::MemoryRegionType_KernelTraceBuffer: return KMemoryLayout::GetPhysicalKernelTraceBufferRegion();
 | 
						|
                            case ams::svc::MemoryRegionType_OnMemoryBootImage: return KMemoryLayout::GetPhysicalOnMemoryBootImageRegion();
 | 
						|
                            case ams::svc::MemoryRegionType_DTB:               return KMemoryLayout::GetPhysicalDTBRegion();
 | 
						|
                            default:                                           return nullptr;
 | 
						|
                        }
 | 
						|
                    }(static_cast<ams::svc::MemoryRegionType>(phys_addr));
 | 
						|
 | 
						|
                    /* Ensure that we found the region. */
 | 
						|
                    R_UNLESS(region != nullptr, svc::ResultNotFound());
 | 
						|
 | 
						|
                    /* Chcek that the region is valid. */
 | 
						|
                    MESOSPHERE_ABORT_UNLESS(region->GetEndAddress() != 0);
 | 
						|
 | 
						|
                    R_TRY(pt.QueryStaticMapping(std::addressof(found_address), region->GetAddress(), region->GetSize()));
 | 
						|
                    found_size = region->GetSize();
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            /* We succeeded. */
 | 
						|
            MESOSPHERE_ASSERT(found_address != Null<KProcessAddress>);
 | 
						|
            MESOSPHERE_ASSERT(found_size    != 0);
 | 
						|
            if (out_address != nullptr) {
 | 
						|
                *out_address = GetInteger(found_address);
 | 
						|
            }
 | 
						|
            if (out_size != nullptr) {
 | 
						|
                *out_size = found_size;
 | 
						|
            }
 | 
						|
            R_SUCCEED();
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    /* =============================    64 ABI    ============================= */
 | 
						|
 | 
						|
    Result QueryPhysicalAddress64(ams::svc::lp64::PhysicalMemoryInfo *out_info, ams::svc::Address address) {
 | 
						|
        R_RETURN(QueryPhysicalAddress(out_info, address));
 | 
						|
    }
 | 
						|
 | 
						|
    Result QueryIoMapping64(ams::svc::Address *out_address, ams::svc::Size *out_size, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) {
 | 
						|
        static_assert(sizeof(*out_address) == sizeof(uintptr_t));
 | 
						|
        static_assert(sizeof(*out_size)    == sizeof(size_t));
 | 
						|
        R_RETURN(QueryIoMapping(reinterpret_cast<uintptr_t *>(out_address), reinterpret_cast<size_t *>(out_size), physical_address, size));
 | 
						|
    }
 | 
						|
 | 
						|
    Result LegacyQueryIoMapping64(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) {
 | 
						|
        static_assert(sizeof(*out_address) == sizeof(uintptr_t));
 | 
						|
        R_RETURN(QueryIoMapping(reinterpret_cast<uintptr_t *>(out_address), nullptr, physical_address, size));
 | 
						|
    }
 | 
						|
 | 
						|
    /* ============================= 64From32 ABI ============================= */
 | 
						|
 | 
						|
    Result QueryPhysicalAddress64From32(ams::svc::ilp32::PhysicalMemoryInfo *out_info, ams::svc::Address address) {
 | 
						|
        ams::svc::PhysicalMemoryInfo info = {};
 | 
						|
        R_TRY(QueryPhysicalAddress(std::addressof(info), address));
 | 
						|
 | 
						|
        *out_info = {
 | 
						|
            .physical_address = info.physical_address,
 | 
						|
            .virtual_address  = static_cast<u32>(info.virtual_address),
 | 
						|
            .size             = static_cast<u32>(info.size),
 | 
						|
        };
 | 
						|
        R_SUCCEED();
 | 
						|
    }
 | 
						|
 | 
						|
    Result QueryIoMapping64From32(ams::svc::Address *out_address, ams::svc::Size *out_size, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) {
 | 
						|
        static_assert(sizeof(*out_address) == sizeof(uintptr_t));
 | 
						|
        static_assert(sizeof(*out_size)    == sizeof(size_t));
 | 
						|
        R_RETURN(QueryIoMapping(reinterpret_cast<uintptr_t *>(out_address), reinterpret_cast<size_t *>(out_size), physical_address, size));
 | 
						|
    }
 | 
						|
 | 
						|
    Result LegacyQueryIoMapping64From32(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) {
 | 
						|
        static_assert(sizeof(*out_address) == sizeof(uintptr_t));
 | 
						|
        R_RETURN(QueryIoMapping(reinterpret_cast<uintptr_t *>(out_address), nullptr, physical_address, size));
 | 
						|
    }
 | 
						|
 | 
						|
}
 |