mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
kern: add SvcQueryIoMapping (NOTE: pre-10.x, ABI needs update)
This commit is contained in:
parent
57867d6ced
commit
18698bf1d3
6 changed files with 204 additions and 2 deletions
|
@ -56,6 +56,14 @@ namespace ams::kern::arch::arm64 {
|
||||||
return this->page_table.QueryInfo(out_info, out_page_info, addr);
|
return this->page_table.QueryInfo(out_info, out_page_info, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result QueryStaticMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const {
|
||||||
|
return this->page_table.QueryStaticMapping(out, address, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result QueryIoMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const {
|
||||||
|
return this->page_table.QueryIoMapping(out, address, size);
|
||||||
|
}
|
||||||
|
|
||||||
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
|
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
|
||||||
return this->page_table.MapMemory(dst_address, src_address, size);
|
return this->page_table.MapMemory(dst_address, src_address, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,6 +268,16 @@ namespace ams::kern {
|
||||||
MESOSPHERE_INIT_ABORT();
|
MESOSPHERE_INIT_ABORT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator TryFindFirstRegionByType(u32 type_id) {
|
||||||
|
for (auto it = this->begin(); it != this->end(); it++) {
|
||||||
|
if (it->GetType() == type_id) {
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->end();
|
||||||
|
}
|
||||||
|
|
||||||
iterator FindFirstDerivedRegion(u32 type_id) {
|
iterator FindFirstDerivedRegion(u32 type_id) {
|
||||||
for (auto it = this->begin(); it != this->end(); it++) {
|
for (auto it = this->begin(); it != this->end(); it++) {
|
||||||
if (it->IsDerivedFrom(type_id)) {
|
if (it->IsDerivedFrom(type_id)) {
|
||||||
|
@ -277,6 +287,16 @@ namespace ams::kern {
|
||||||
MESOSPHERE_INIT_ABORT();
|
MESOSPHERE_INIT_ABORT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator TryFindFirstDerivedRegion(u32 type_id) {
|
||||||
|
for (auto it = this->begin(); it != this->end(); it++) {
|
||||||
|
if (it->IsDerivedFrom(type_id)) {
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->end();
|
||||||
|
}
|
||||||
|
|
||||||
DerivedRegionExtents GetDerivedRegionExtents(u32 type_id) const {
|
DerivedRegionExtents GetDerivedRegionExtents(u32 type_id) const {
|
||||||
DerivedRegionExtents extents;
|
DerivedRegionExtents extents;
|
||||||
|
|
||||||
|
@ -504,6 +524,33 @@ namespace ams::kern {
|
||||||
return *GetVirtualLinearMemoryRegionTree().FindContainingRegion(GetInteger(address));
|
return *GetVirtualLinearMemoryRegionTree().FindContainingRegion(GetInteger(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NOINLINE const KMemoryRegion *TryGetKernelTraceBufferRegion() {
|
||||||
|
auto &tree = GetPhysicalMemoryRegionTree();
|
||||||
|
if (KMemoryRegionTree::const_iterator it = tree.TryFindFirstDerivedRegion(KMemoryRegionType_KernelTraceBuffer); it != tree.end()) {
|
||||||
|
return std::addressof(*it);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static NOINLINE const KMemoryRegion *TryGetOnMemoryBootImageRegion() {
|
||||||
|
auto &tree = GetPhysicalMemoryRegionTree();
|
||||||
|
if (KMemoryRegionTree::const_iterator it = tree.TryFindFirstDerivedRegion(KMemoryRegionType_OnMemoryBootImage); it != tree.end()) {
|
||||||
|
return std::addressof(*it);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static NOINLINE const KMemoryRegion *TryGetDTBRegion() {
|
||||||
|
auto &tree = GetPhysicalMemoryRegionTree();
|
||||||
|
if (KMemoryRegionTree::const_iterator it = tree.TryFindFirstDerivedRegion(KMemoryRegionType_DTB); it != tree.end()) {
|
||||||
|
return std::addressof(*it);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static NOINLINE bool IsHeapPhysicalAddress(const KMemoryRegion **out, KPhysicalAddress address, const KMemoryRegion *hint = nullptr) {
|
static NOINLINE bool IsHeapPhysicalAddress(const KMemoryRegion **out, KPhysicalAddress address, const KMemoryRegion *hint = nullptr) {
|
||||||
auto &tree = GetPhysicalLinearMemoryRegionTree();
|
auto &tree = GetPhysicalLinearMemoryRegionTree();
|
||||||
KMemoryRegionTree::const_iterator it = tree.end();
|
KMemoryRegionTree::const_iterator it = tree.end();
|
||||||
|
|
|
@ -248,6 +248,9 @@ namespace ams::kern {
|
||||||
Result UnlockMemory(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, KMemoryPermission new_perm, u32 lock_attr, const KPageGroup *pg);
|
Result UnlockMemory(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, KMemoryPermission new_perm, u32 lock_attr, const KPageGroup *pg);
|
||||||
|
|
||||||
Result QueryInfoImpl(KMemoryInfo *out_info, ams::svc::PageInfo *out_page, KProcessAddress address) const;
|
Result QueryInfoImpl(KMemoryInfo *out_info, ams::svc::PageInfo *out_page, KProcessAddress address) const;
|
||||||
|
|
||||||
|
Result QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, KMemoryState state) const;
|
||||||
|
|
||||||
Result AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, const KPageProperties properties);
|
Result AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, const KPageProperties properties);
|
||||||
Result MapPageGroupImpl(PageLinkedList *page_list, KProcessAddress address, const KPageGroup &pg, const KPageProperties properties, bool reuse_ll);
|
Result MapPageGroupImpl(PageLinkedList *page_list, KProcessAddress address, const KPageGroup &pg, const KPageProperties properties, bool reuse_ll);
|
||||||
|
|
||||||
|
@ -271,6 +274,8 @@ namespace ams::kern {
|
||||||
Result SetHeapSize(KProcessAddress *out, size_t size);
|
Result SetHeapSize(KProcessAddress *out, size_t size);
|
||||||
Result SetMaxHeapSize(size_t size);
|
Result SetMaxHeapSize(size_t size);
|
||||||
Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const;
|
Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const;
|
||||||
|
Result QueryStaticMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { return this->QueryMappingImpl(out, address, size, KMemoryState_Static); }
|
||||||
|
Result QueryIoMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { return this->QueryMappingImpl(out, address, size, KMemoryState_Io); }
|
||||||
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||||
|
|
|
@ -585,6 +585,76 @@ namespace ams::kern {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result KPageTableBase::QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, KMemoryState state) const {
|
||||||
|
MESOSPHERE_ASSERT(!this->IsLockedByCurrentThread());
|
||||||
|
MESOSPHERE_ASSERT(out != nullptr);
|
||||||
|
|
||||||
|
const KProcessAddress region_start = this->GetRegionAddress(state);
|
||||||
|
const size_t region_size = this->GetRegionSize(state);
|
||||||
|
|
||||||
|
/* Check that the address/size are potentially valid. */
|
||||||
|
R_UNLESS((address < address + size), svc::ResultNotFound());
|
||||||
|
|
||||||
|
/* Lock the table. */
|
||||||
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
|
auto &impl = this->GetImpl();
|
||||||
|
|
||||||
|
/* Begin traversal. */
|
||||||
|
TraversalContext context;
|
||||||
|
TraversalEntry cur_entry = {};
|
||||||
|
bool cur_valid = false;
|
||||||
|
TraversalEntry next_entry;
|
||||||
|
bool next_valid;
|
||||||
|
size_t tot_size = false;
|
||||||
|
|
||||||
|
next_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), region_start);
|
||||||
|
next_entry.block_size = (next_entry.block_size - (GetInteger(address) & (next_entry.block_size - 1)));
|
||||||
|
|
||||||
|
/* Iterate, looking for entry. */
|
||||||
|
while (true) {
|
||||||
|
if ((!next_valid && !cur_valid) || (next_valid && cur_valid && next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size)) {
|
||||||
|
cur_entry.block_size += next_entry.block_size;
|
||||||
|
} else {
|
||||||
|
if (cur_valid && cur_entry.phys_addr <= address && address + size <= cur_entry.phys_addr + cur_entry.block_size) {
|
||||||
|
/* Check if this region is valid. */
|
||||||
|
const KProcessAddress mapped_address = (region_start + tot_size) + (address - cur_entry.phys_addr);
|
||||||
|
if (R_SUCCEEDED(this->CheckMemoryState(mapped_address, size, KMemoryState_All, state, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None))) {
|
||||||
|
/* It is! */
|
||||||
|
*out = mapped_address;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update tracking variables. */
|
||||||
|
tot_size += cur_entry.block_size;
|
||||||
|
cur_entry = next_entry;
|
||||||
|
cur_valid = next_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur_entry.block_size + tot_size >= region_size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the last entry. */
|
||||||
|
R_UNLESS(cur_valid, svc::ResultNotFound());
|
||||||
|
R_UNLESS(cur_entry.phys_addr <= address, svc::ResultNotFound());
|
||||||
|
R_UNLESS(address + size <= cur_entry.phys_addr + cur_entry.block_size, svc::ResultNotFound());
|
||||||
|
|
||||||
|
/* Check if the last region is valid. */
|
||||||
|
const KProcessAddress mapped_address = (region_start + tot_size) + (address - cur_entry.phys_addr);
|
||||||
|
R_TRY_CATCH(this->CheckMemoryState(mapped_address, size, KMemoryState_All, state, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None)) {
|
||||||
|
R_CONVERT_ALL(svc::ResultNotFound());
|
||||||
|
} R_END_TRY_CATCH;
|
||||||
|
|
||||||
|
/* We found the region. */
|
||||||
|
*out = mapped_address;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
Result KPageTableBase::MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
|
Result KPageTableBase::MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
|
||||||
/* Lock the table. */
|
/* Lock the table. */
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
|
@ -21,7 +21,69 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
namespace {
|
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<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);
|
||||||
|
|
||||||
|
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<ams::svc::MemoryRegionType>(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<KProcessAddress>);
|
||||||
|
MESOSPHERE_ASSERT(found_size != 0);
|
||||||
|
if (out_address != nullptr) {
|
||||||
|
*out_address = GetInteger(found_address);
|
||||||
|
}
|
||||||
|
if (out_size != nullptr) {
|
||||||
|
*out_size = found_size;
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +94,8 @@ namespace ams::kern::svc {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result QueryIoMapping64(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) {
|
Result QueryIoMapping64(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcQueryIoMapping64 was called.");
|
static_assert(sizeof(*out_address) == sizeof(uintptr_t));
|
||||||
|
return QueryIoMapping(reinterpret_cast<uintptr_t *>(out_address), nullptr, physical_address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================= 64From32 ABI ============================= */
|
/* ============================= 64From32 ABI ============================= */
|
||||||
|
@ -42,7 +105,8 @@ namespace ams::kern::svc {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result QueryIoMapping64From32(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) {
|
Result QueryIoMapping64From32(ams::svc::Address *out_address, ams::svc::PhysicalAddress physical_address, ams::svc::Size size) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcQueryIoMapping64From32 was called.");
|
static_assert(sizeof(*out_address) == sizeof(uintptr_t));
|
||||||
|
return QueryIoMapping(reinterpret_cast<uintptr_t *>(out_address), nullptr, physical_address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,14 @@ namespace ams::svc {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MemoryRegionType {
|
||||||
|
MemoryRegionType_None = 0,
|
||||||
|
MemoryRegionType_KernelTraceBuffer = 1,
|
||||||
|
MemoryRegionType_OnMemoryBootImage = 2,
|
||||||
|
MemoryRegionType_DTB = 3,
|
||||||
|
MemoryRegionType_Count,
|
||||||
|
};
|
||||||
|
|
||||||
/* Info Types. */
|
/* Info Types. */
|
||||||
enum InfoType : u32 {
|
enum InfoType : u32 {
|
||||||
InfoType_CoreMask = 0,
|
InfoType_CoreMask = 0,
|
||||||
|
|
Loading…
Reference in a new issue