mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-23 04:41:12 +00:00
kern: add infra (but not impl) for all DeviceAddressSpace svcs
This commit is contained in:
parent
863515a3b5
commit
0d3aa13f70
11 changed files with 303 additions and 13 deletions
|
@ -104,6 +104,18 @@ namespace ams::kern::arch::arm64 {
|
||||||
return this->page_table.MakeAndOpenPageGroup(out, address, num_pages, state_mask, state, perm_mask, perm, attr_mask, attr);
|
return this->page_table.MakeAndOpenPageGroup(out, address, num_pages, state_mask, state, perm_mask, perm, attr_mask, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result MakeAndOpenPageGroupContiguous(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) {
|
||||||
|
return this->page_table.MakeAndOpenPageGroupContiguous(out, address, num_pages, state_mask, state, perm_mask, perm, attr_mask, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
|
||||||
|
return this->page_table.LockForDeviceAddressSpace(out, address, size, perm, is_aligned);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) {
|
||||||
|
return this->page_table.UnlockForDeviceAddressSpace(address, size);
|
||||||
|
}
|
||||||
|
|
||||||
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size) {
|
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size) {
|
||||||
return this->page_table.LockForIpcUserBuffer(out, address, size);
|
return this->page_table.LockForIpcUserBuffer(out, address, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,9 @@ namespace ams::kern::board::nintendo::nx {
|
||||||
|
|
||||||
Result Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size);
|
Result Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size);
|
||||||
Result Detach(ams::svc::DeviceName device_name);
|
Result Detach(ams::svc::DeviceName device_name);
|
||||||
|
|
||||||
|
Result Map(size_t *out_mapped_size, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings);
|
||||||
|
Result Unmap(const KPageGroup &pg, KDeviceVirtualAddress device_address);
|
||||||
public:
|
public:
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
};
|
};
|
||||||
|
|
|
@ -389,6 +389,30 @@ namespace ams::kern {
|
||||||
this->num_pages -= block->num_pages;
|
this->num_pages -= block->num_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr void ShareToDevice(KMemoryPermission new_perm) {
|
||||||
|
/* We must either be shared or have a zero lock count. */
|
||||||
|
MESOSPHERE_ASSERT((this->attribute & KMemoryAttribute_DeviceShared) == KMemoryAttribute_DeviceShared || this->device_use_count == 0);
|
||||||
|
|
||||||
|
/* Share. */
|
||||||
|
const u16 new_count = ++this->device_use_count;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(new_count > 0);
|
||||||
|
|
||||||
|
this->attribute = static_cast<KMemoryAttribute>(this->attribute | KMemoryAttribute_DeviceShared);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void UnshareToDevice(KMemoryPermission new_perm) {
|
||||||
|
/* We must be shared. */
|
||||||
|
MESOSPHERE_ASSERT((this->attribute & KMemoryAttribute_DeviceShared) == KMemoryAttribute_DeviceShared);
|
||||||
|
|
||||||
|
/* Unhare. */
|
||||||
|
const u16 old_count = this->device_use_count--;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(old_count > 0);
|
||||||
|
|
||||||
|
if (old_count == 1) {
|
||||||
|
this->attribute = static_cast<KMemoryAttribute>(this->attribute & ~KMemoryAttribute_DeviceShared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr void LockForIpc(KMemoryPermission new_perm) {
|
constexpr void LockForIpc(KMemoryPermission new_perm) {
|
||||||
/* We must either be locked or have a zero lock count. */
|
/* We must either be locked or have a zero lock count. */
|
||||||
MESOSPHERE_ASSERT((this->attribute & KMemoryAttribute_IpcLocked) == KMemoryAttribute_IpcLocked || this->ipc_lock_count == 0);
|
MESOSPHERE_ASSERT((this->attribute & KMemoryAttribute_IpcLocked) == KMemoryAttribute_IpcLocked || this->ipc_lock_count == 0);
|
||||||
|
|
|
@ -300,7 +300,10 @@ namespace ams::kern {
|
||||||
Result UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state);
|
Result UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state);
|
||||||
|
|
||||||
Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
|
Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
|
||||||
|
Result MakeAndOpenPageGroupContiguous(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
|
||||||
|
|
||||||
|
Result LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned);
|
||||||
|
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size);
|
||||||
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size);
|
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size);
|
||||||
Result UnlockForIpcUserBuffer(KProcessAddress address, size_t size);
|
Result UnlockForIpcUserBuffer(KProcessAddress address, size_t size);
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace ams::kern::svc {
|
||||||
/* 105 */ using ::ams::svc::ResultOutOfHandles;
|
/* 105 */ using ::ams::svc::ResultOutOfHandles;
|
||||||
/* 106 */ using ::ams::svc::ResultInvalidCurrentMemory;
|
/* 106 */ using ::ams::svc::ResultInvalidCurrentMemory;
|
||||||
|
|
||||||
/* 108 */ using ::ams::svc::ResultInvalidNewMemoryPermissions;
|
/* 108 */ using ::ams::svc::ResultInvalidNewMemoryPermission;
|
||||||
|
|
||||||
/* 110 */ using ::ams::svc::ResultInvalidMemoryRegion;
|
/* 110 */ using ::ams::svc::ResultInvalidMemoryRegion;
|
||||||
|
|
||||||
|
|
|
@ -583,4 +583,12 @@ namespace ams::kern::board::nintendo::nx {
|
||||||
MESOSPHERE_UNIMPLEMENTED();
|
MESOSPHERE_UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result KDevicePageTable::Map(size_t *out_mapped_size, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings) {
|
||||||
|
MESOSPHERE_UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KDevicePageTable::Unmap(const KPageGroup &pg, KDeviceVirtualAddress device_address) {
|
||||||
|
MESOSPHERE_UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,15 +57,71 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KDeviceAddressSpace::Detach(ams::svc::DeviceName device_name) {
|
Result KDeviceAddressSpace::Detach(ams::svc::DeviceName device_name) {
|
||||||
MESOSPHERE_UNIMPLEMENTED();
|
/* Lock the address space. */
|
||||||
|
KScopedLightLock lk(this->lock);
|
||||||
|
|
||||||
|
/* Detach. */
|
||||||
|
return this->table.Detach(device_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KDeviceAddressSpace::Map(size_t *out_mapped_size, KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool refresh_mappings) {
|
Result KDeviceAddressSpace::Map(size_t *out_mapped_size, KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address, ams::svc::MemoryPermission device_perm, bool is_aligned, bool refresh_mappings) {
|
||||||
MESOSPHERE_UNIMPLEMENTED();
|
/* Check that the address falls within the space. */
|
||||||
|
R_UNLESS((this->space_address <= device_address && device_address + size - 1 <= this->space_address + this->space_size - 1), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
/* Lock the address space. */
|
||||||
|
KScopedLightLock lk(this->lock);
|
||||||
|
|
||||||
|
/* Lock the pages. */
|
||||||
|
KPageGroup pg(page_table->GetBlockInfoManager());
|
||||||
|
R_TRY(page_table->LockForDeviceAddressSpace(std::addressof(pg), process_address, size, ConvertToKMemoryPermission(device_perm), is_aligned));
|
||||||
|
|
||||||
|
/* Ensure that if we fail, we don't keep unmapped pages locked. */
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
if (*out_mapped_size != size) {
|
||||||
|
page_table->UnlockForDeviceAddressSpace(process_address + *out_mapped_size, size - *out_mapped_size);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Map the pages. */
|
||||||
|
{
|
||||||
|
/* Clear the output size to zero on failure. */
|
||||||
|
auto map_guard = SCOPE_GUARD { *out_mapped_size = 0; };
|
||||||
|
|
||||||
|
/* Perform the mapping. */
|
||||||
|
R_TRY(this->table.Map(out_mapped_size, pg, device_address, device_perm, refresh_mappings));
|
||||||
|
|
||||||
|
/* We succeeded, so cancel our guard. */
|
||||||
|
map_guard.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KDeviceAddressSpace::Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address) {
|
Result KDeviceAddressSpace::Unmap(KProcessPageTable *page_table, KProcessAddress process_address, size_t size, u64 device_address) {
|
||||||
MESOSPHERE_UNIMPLEMENTED();
|
/* Check that the address falls within the space. */
|
||||||
|
R_UNLESS((this->space_address <= device_address && device_address + size - 1 <= this->space_address + this->space_size - 1), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
/* Lock the address space. */
|
||||||
|
KScopedLightLock lk(this->lock);
|
||||||
|
|
||||||
|
/* Make and open a page group for the unmapped region. */
|
||||||
|
KPageGroup pg(page_table->GetBlockInfoManager());
|
||||||
|
R_TRY(page_table->MakeAndOpenPageGroupContiguous(std::addressof(pg), process_address, size / PageSize,
|
||||||
|
KMemoryState_FlagCanDeviceMap, KMemoryState_FlagCanDeviceMap,
|
||||||
|
KMemoryPermission_None, KMemoryPermission_None,
|
||||||
|
KMemoryAttribute_AnyLocked | KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared));
|
||||||
|
|
||||||
|
/* Ensure the page group is closed on scope exit. */
|
||||||
|
ON_SCOPE_EXIT { pg.Close(); };
|
||||||
|
|
||||||
|
/* Unmap. */
|
||||||
|
R_TRY(this->table.Unmap(pg, device_address));
|
||||||
|
|
||||||
|
/* Unlock the pages. */
|
||||||
|
R_TRY(page_table->UnlockForDeviceAddressSpace(process_address, size));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1370,6 +1370,85 @@ namespace ams::kern {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result KPageTableBase::MakeAndOpenPageGroupContiguous(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) {
|
||||||
|
/* Ensure that the page group isn't null. */
|
||||||
|
MESOSPHERE_ASSERT(out != nullptr);
|
||||||
|
|
||||||
|
/* Make sure that the region we're mapping is valid for the table. */
|
||||||
|
const size_t size = num_pages * PageSize;
|
||||||
|
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
/* Lock the table. */
|
||||||
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
|
/* Check if state allows us to create the group. */
|
||||||
|
R_TRY(this->CheckMemoryStateContiguous(address, size, state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr));
|
||||||
|
|
||||||
|
/* Create a new page group for the region. */
|
||||||
|
R_TRY(this->MakePageGroup(*out, address, num_pages));
|
||||||
|
|
||||||
|
/* Open a new reference to the pages in the group. */
|
||||||
|
out->Open();
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KPageTableBase::LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
|
||||||
|
/* Lightly validate the range before doing anything else. */
|
||||||
|
const size_t num_pages = size / PageSize;
|
||||||
|
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
/* Lock the table. */
|
||||||
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
|
/* Check the memory state. */
|
||||||
|
const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap);
|
||||||
|
R_TRY(this->CheckMemoryState(address, size, test_state, test_state, perm, perm, KMemoryAttribute_AnyLocked | KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, 0, KMemoryAttribute_DeviceShared));
|
||||||
|
|
||||||
|
/* Make the page group, if we should. */
|
||||||
|
if (out != nullptr) {
|
||||||
|
R_TRY(this->MakePageGroup(*out, address, num_pages));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create an update allocator. */
|
||||||
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
|
R_TRY(allocator.GetResult());
|
||||||
|
|
||||||
|
/* Update the memory blocks. */
|
||||||
|
this->memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::ShareToDevice, KMemoryPermission_None);
|
||||||
|
|
||||||
|
/* Open the page group. */
|
||||||
|
if (out != nullptr) {
|
||||||
|
out->Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KPageTableBase::UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) {
|
||||||
|
/* Lightly validate the range before doing anything else. */
|
||||||
|
const size_t num_pages = size / PageSize;
|
||||||
|
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
/* Lock the table. */
|
||||||
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
|
/* Check the memory state. */
|
||||||
|
R_TRY(this->CheckMemoryStateContiguous(address, size,
|
||||||
|
KMemoryState_FlagCanDeviceMap, KMemoryState_FlagCanDeviceMap,
|
||||||
|
KMemoryPermission_None, KMemoryPermission_None,
|
||||||
|
KMemoryAttribute_AnyLocked | KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared));
|
||||||
|
|
||||||
|
/* Create an update allocator. */
|
||||||
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
|
R_TRY(allocator.GetResult());
|
||||||
|
|
||||||
|
/* Update the memory blocks. */
|
||||||
|
this->memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::UnshareToDevice, KMemoryPermission_None);
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
Result KPageTableBase::LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size) {
|
Result KPageTableBase::LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size) {
|
||||||
return this->LockMemoryAndOpen(nullptr, out, address, size,
|
return this->LockMemoryAndOpen(nullptr, out, address, size,
|
||||||
KMemoryState_FlagCanIpcUserBuffer, KMemoryState_FlagCanIpcUserBuffer,
|
KMemoryState_FlagCanIpcUserBuffer, KMemoryState_FlagCanIpcUserBuffer,
|
||||||
|
|
|
@ -21,6 +21,12 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline u64 DeviceAddressSpaceAlignMask = (1ul << 22) - 1;
|
||||||
|
|
||||||
|
constexpr bool IsProcessAndDeviceAligned(uint64_t process_address, uint64_t device_address) {
|
||||||
|
return (process_address & DeviceAddressSpaceAlignMask) == (device_address & DeviceAddressSpaceAlignMask);
|
||||||
|
}
|
||||||
|
|
||||||
Result CreateDeviceAddressSpace(ams::svc::Handle *out, uint64_t das_address, uint64_t das_size) {
|
Result CreateDeviceAddressSpace(ams::svc::Handle *out, uint64_t das_address, uint64_t das_size) {
|
||||||
/* Validate input. */
|
/* Validate input. */
|
||||||
R_UNLESS(util::IsAligned(das_address, PageSize), svc::ResultInvalidMemoryRegion());
|
R_UNLESS(util::IsAligned(das_address, PageSize), svc::ResultInvalidMemoryRegion());
|
||||||
|
@ -62,6 +68,97 @@ namespace ams::kern::svc {
|
||||||
return das->Detach(device_name);
|
return das->Detach(device_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool IsValidDeviceMemoryPermission(ams::svc::MemoryPermission device_perm) {
|
||||||
|
switch (device_perm) {
|
||||||
|
case ams::svc::MemoryPermission_Read:
|
||||||
|
case ams::svc::MemoryPermission_Write:
|
||||||
|
case ams::svc::MemoryPermission_ReadWrite:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MapDeviceAddressSpace(size_t *out_mapped_size, ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings) {
|
||||||
|
/* Validate input. */
|
||||||
|
R_UNLESS(util::IsAligned(process_address, PageSize), svc::ResultInvalidAddress());
|
||||||
|
R_UNLESS(util::IsAligned(device_address, PageSize), svc::ResultInvalidAddress());
|
||||||
|
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||||
|
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||||
|
R_UNLESS((process_address < process_address + size), svc::ResultInvalidCurrentMemory());
|
||||||
|
R_UNLESS((device_address < device_address + size), svc::ResultInvalidMemoryRegion());
|
||||||
|
R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), svc::ResultInvalidCurrentMemory());
|
||||||
|
R_UNLESS(IsValidDeviceMemoryPermission(device_perm), svc::ResultInvalidNewMemoryPermission());
|
||||||
|
|
||||||
|
/* Get the device address space. */
|
||||||
|
KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject<KDeviceAddressSpace>(das_handle);
|
||||||
|
R_UNLESS(das.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
|
/* Get the process. */
|
||||||
|
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle);
|
||||||
|
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
|
/* Validate that the process address is within range. */
|
||||||
|
auto &page_table = process->GetPageTable();
|
||||||
|
R_UNLESS(page_table.Contains(process_address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
/* Map. */
|
||||||
|
return das->Map(out_mapped_size, std::addressof(page_table), KProcessAddress(process_address), size, device_address, device_perm, refresh_mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MapDeviceAddressSpaceAligned(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||||
|
/* Validate input. */
|
||||||
|
R_UNLESS(util::IsAligned(process_address, PageSize), svc::ResultInvalidAddress());
|
||||||
|
R_UNLESS(util::IsAligned(device_address, PageSize), svc::ResultInvalidAddress());
|
||||||
|
R_UNLESS(IsProcessAndDeviceAligned(process_address, device_address), svc::ResultInvalidAddress());
|
||||||
|
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||||
|
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||||
|
R_UNLESS((process_address < process_address + size), svc::ResultInvalidCurrentMemory());
|
||||||
|
R_UNLESS((device_address < device_address + size), svc::ResultInvalidMemoryRegion());
|
||||||
|
R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), svc::ResultInvalidCurrentMemory());
|
||||||
|
R_UNLESS(IsValidDeviceMemoryPermission(device_perm), svc::ResultInvalidNewMemoryPermission());
|
||||||
|
|
||||||
|
/* Get the device address space. */
|
||||||
|
KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject<KDeviceAddressSpace>(das_handle);
|
||||||
|
R_UNLESS(das.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
|
/* Get the process. */
|
||||||
|
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle);
|
||||||
|
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
|
/* Validate that the process address is within range. */
|
||||||
|
auto &page_table = process->GetPageTable();
|
||||||
|
R_UNLESS(page_table.Contains(process_address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
/* Map. */
|
||||||
|
return das->MapAligned(std::addressof(page_table), KProcessAddress(process_address), size, device_address, device_perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnmapDeviceAddressSpace(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, size_t size, uint64_t device_address) {
|
||||||
|
/* Validate input. */
|
||||||
|
R_UNLESS(util::IsAligned(process_address, PageSize), svc::ResultInvalidAddress());
|
||||||
|
R_UNLESS(util::IsAligned(device_address, PageSize), svc::ResultInvalidAddress());
|
||||||
|
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||||
|
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||||
|
R_UNLESS((process_address < process_address + size), svc::ResultInvalidCurrentMemory());
|
||||||
|
R_UNLESS((device_address < device_address + size), svc::ResultInvalidMemoryRegion());
|
||||||
|
R_UNLESS((process_address == static_cast<uintptr_t>(process_address)), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
/* Get the device address space. */
|
||||||
|
KScopedAutoObject das = GetCurrentProcess().GetHandleTable().GetObject<KDeviceAddressSpace>(das_handle);
|
||||||
|
R_UNLESS(das.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
|
/* Get the process. */
|
||||||
|
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle);
|
||||||
|
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
|
/* Validate that the process address is within range. */
|
||||||
|
auto &page_table = process->GetPageTable();
|
||||||
|
R_UNLESS(page_table.Contains(process_address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
return das->Unmap(std::addressof(page_table), KProcessAddress(process_address), size, device_address);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================= 64 ABI ============================= */
|
/* ============================= 64 ABI ============================= */
|
||||||
|
@ -79,19 +176,21 @@ namespace ams::kern::svc {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapDeviceAddressSpaceByForce64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
Result MapDeviceAddressSpaceByForce64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcMapDeviceAddressSpaceByForce64 was called.");
|
size_t dummy_map_size;
|
||||||
|
return MapDeviceAddressSpace(std::addressof(dummy_map_size), das_handle, process_handle, process_address, size, device_address, device_perm, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapDeviceAddressSpaceAligned64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
Result MapDeviceAddressSpaceAligned64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcMapDeviceAddressSpaceAligned64 was called.");
|
return MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, device_perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapDeviceAddressSpace64(ams::svc::Size *out_mapped_size, ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
Result MapDeviceAddressSpace64(ams::svc::Size *out_mapped_size, ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcMapDeviceAddressSpace64 was called.");
|
static_assert(sizeof(*out_mapped_size) == sizeof(size_t));
|
||||||
|
return MapDeviceAddressSpace(reinterpret_cast<size_t *>(out_mapped_size), das_handle, process_handle, process_address, size, device_address, device_perm, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result UnmapDeviceAddressSpace64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address) {
|
Result UnmapDeviceAddressSpace64(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcUnmapDeviceAddressSpace64 was called.");
|
return UnmapDeviceAddressSpace(das_handle, process_handle, process_address, size, device_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================= 64From32 ABI ============================= */
|
/* ============================= 64From32 ABI ============================= */
|
||||||
|
@ -109,19 +208,21 @@ namespace ams::kern::svc {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapDeviceAddressSpaceByForce64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
Result MapDeviceAddressSpaceByForce64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcMapDeviceAddressSpaceByForce64From32 was called.");
|
size_t dummy_map_size;
|
||||||
|
return MapDeviceAddressSpace(std::addressof(dummy_map_size), das_handle, process_handle, process_address, size, device_address, device_perm, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapDeviceAddressSpaceAligned64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
Result MapDeviceAddressSpaceAligned64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcMapDeviceAddressSpaceAligned64From32 was called.");
|
return MapDeviceAddressSpaceAligned(das_handle, process_handle, process_address, size, device_address, device_perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapDeviceAddressSpace64From32(ams::svc::Size *out_mapped_size, ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
Result MapDeviceAddressSpace64From32(ams::svc::Size *out_mapped_size, ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address, ams::svc::MemoryPermission device_perm) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcMapDeviceAddressSpace64From32 was called.");
|
static_assert(sizeof(*out_mapped_size) == sizeof(size_t));
|
||||||
|
return MapDeviceAddressSpace(reinterpret_cast<size_t *>(out_mapped_size), das_handle, process_handle, process_address, size, device_address, device_perm, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result UnmapDeviceAddressSpace64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address) {
|
Result UnmapDeviceAddressSpace64From32(ams::svc::Handle das_handle, ams::svc::Handle process_handle, uint64_t process_address, ams::svc::Size size, uint64_t device_address) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcUnmapDeviceAddressSpace64From32 was called.");
|
return UnmapDeviceAddressSpace(das_handle, process_handle, process_address, size, device_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,10 @@ namespace ams::kern::svc {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
Result ReadWriteRegister(uint32_t *out, ams::svc::PhysicalAddress address, uint32_t mask, uint32_t value) {
|
Result ReadWriteRegister(uint32_t *out, ams::svc::PhysicalAddress address, uint32_t mask, uint32_t value) {
|
||||||
|
/* Clear the output unconditionally. */
|
||||||
|
*out = 0;
|
||||||
|
|
||||||
|
/* Read/write the register. */
|
||||||
return KSystemControl::ReadWriteRegister(out, address, mask, value);
|
return KSystemControl::ReadWriteRegister(out, address, mask, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace ams::svc {
|
||||||
R_DEFINE_ERROR_RESULT(OutOfHandles, 105);
|
R_DEFINE_ERROR_RESULT(OutOfHandles, 105);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidCurrentMemory, 106);
|
R_DEFINE_ERROR_RESULT(InvalidCurrentMemory, 106);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(InvalidNewMemoryPermissions, 108);
|
R_DEFINE_ERROR_RESULT(InvalidNewMemoryPermission, 108);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(InvalidMemoryRegion, 110);
|
R_DEFINE_ERROR_RESULT(InvalidMemoryRegion, 110);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue