/* * Copyright (c) 2018-2020 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 . */ #include namespace ams::kern::svc { /* ============================= Common ============================= */ namespace { 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; 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); if (aligned) { /* 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; } else { /* TODO: Older kernel ABI compatibility. */ /* 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 *region; switch (static_cast(phys_addr)) { case ams::svc::MemoryRegionType_KernelTraceBuffer: region = KMemoryLayout::TryGetKernelTraceBufferRegion(); break; case ams::svc::MemoryRegionType_OnMemoryBootImage: region = KMemoryLayout::TryGetOnMemoryBootImageRegion(); break; case ams::svc::MemoryRegionType_DTB: region = KMemoryLayout::TryGetDTBRegion(); break; default: region = nullptr; break; } /* Ensure that we found the region. */ R_UNLESS(region != nullptr, svc::ResultNotFound()); R_TRY(pt.QueryStaticMapping(std::addressof(found_address), region->GetAddress(), region->GetSize())); found_size = region->GetSize(); } /* We succeeded. */ MESOSPHERE_ASSERT(found_address != Null); MESOSPHERE_ASSERT(found_size != 0); if (out_address != nullptr) { *out_address = GetInteger(found_address); } if (out_size != nullptr) { *out_size = found_size; } return ResultSuccess(); } } /* ============================= 64 ABI ============================= */ Result QueryPhysicalAddress64(ams::svc::lp64::PhysicalMemoryInfo *out_info, ams::svc::Address address) { MESOSPHERE_PANIC("Stubbed SvcQueryPhysicalAddress64 was called."); } 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)); return QueryIoMapping(reinterpret_cast(out_address), reinterpret_cast(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)); return QueryIoMapping(reinterpret_cast(out_address), nullptr, physical_address, size); } /* ============================= 64From32 ABI ============================= */ Result QueryPhysicalAddress64From32(ams::svc::ilp32::PhysicalMemoryInfo *out_info, ams::svc::Address address) { MESOSPHERE_PANIC("Stubbed SvcQueryPhysicalAddress64From32 was called."); } 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)); return QueryIoMapping(reinterpret_cast(out_address), reinterpret_cast(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)); return QueryIoMapping(reinterpret_cast(out_address), nullptr, physical_address, size); } }