mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
kern: update KMemoryBlockManagerUpdateAllocator api
This commit is contained in:
parent
71a2fe1bb6
commit
281dcf232a
5 changed files with 229 additions and 134 deletions
|
@ -152,26 +152,26 @@ namespace ams::kern::arch::arm64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
constexpr ALWAYS_INLINE u8 GetSoftwareReservedBits() const { return this->GetBits(55, 3); }
|
constexpr ALWAYS_INLINE u8 GetSoftwareReservedBits() const { return this->GetBits(55, 3); }
|
||||||
constexpr ALWAYS_INLINE bool IsHeadMergeDisabled() const { return (this->GetSoftwareReservedBits() & SoftwareReservedBit_DisableMergeHead) != 0; }
|
constexpr ALWAYS_INLINE bool IsHeadMergeDisabled() const { return (this->GetSoftwareReservedBits() & SoftwareReservedBit_DisableMergeHead) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsHeadAndBodyMergeDisabled() const { return (this->GetSoftwareReservedBits() & PageTableEntry::SoftwareReservedBit_DisableMergeHeadAndBody) != 0; }
|
constexpr ALWAYS_INLINE bool IsHeadAndBodyMergeDisabled() const { return (this->GetSoftwareReservedBits() & SoftwareReservedBit_DisableMergeHeadAndBody) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsTailMergeDisabled() const { return (this->GetSoftwareReservedBits() & PageTableEntry::SoftwareReservedBit_DisableMergeHeadTail) != 0; }
|
constexpr ALWAYS_INLINE bool IsTailMergeDisabled() const { return (this->GetSoftwareReservedBits() & SoftwareReservedBit_DisableMergeHeadTail) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsUserExecuteNever() const { return this->GetBits(54, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsHeadOrHeadAndBodyMergeDisabled() const { return (this->GetSoftwareReservedBits() & (SoftwareReservedBit_DisableMergeHead | SoftwareReservedBit_DisableMergeHeadAndBody)) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsUserExecuteNever() const { return this->GetBits(54, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsGlobal() const { return this->GetBits(11, 1) == 0; }
|
constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast<AccessFlag>(this->GetBits(10, 1)); }
|
constexpr ALWAYS_INLINE bool IsGlobal() const { return this->GetBits(11, 1) == 0; }
|
||||||
constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast<Shareable>(this->GetBits(8, 2)); }
|
constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast<AccessFlag>(this->GetBits(10, 1)); }
|
||||||
constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast<PageAttribute>(this->GetBits(2, 3)); }
|
constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast<Shareable>(this->GetBits(8, 2)); }
|
||||||
constexpr ALWAYS_INLINE bool IsReadOnly() const { return this->GetBits(7, 1) != 0; }
|
constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast<PageAttribute>(this->GetBits(2, 3)); }
|
||||||
constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsReadOnly() const { return this->GetBits(7, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsUserAccessible() const { return this->GetBits(6, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsBlock() const { return (this->attributes & ExtensionFlag_TestTableMask) == ExtensionFlag_Valid; }
|
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }
|
||||||
constexpr ALWAYS_INLINE bool IsTable() const { return (this->attributes & ExtensionFlag_TestTableMask) == 2; }
|
constexpr ALWAYS_INLINE bool IsBlock() const { return (this->attributes & ExtensionFlag_TestTableMask) == ExtensionFlag_Valid; }
|
||||||
constexpr ALWAYS_INLINE bool IsEmpty() const { return (this->attributes & ExtensionFlag_TestTableMask) == 0; }
|
constexpr ALWAYS_INLINE bool IsTable() const { return (this->attributes & ExtensionFlag_TestTableMask) == 2; }
|
||||||
constexpr ALWAYS_INLINE bool IsMapped() const { return this->GetBits(0, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsEmpty() const { return (this->attributes & ExtensionFlag_TestTableMask) == 0; }
|
||||||
|
constexpr ALWAYS_INLINE bool IsMapped() const { return this->GetBits(0, 1) != 0; }
|
||||||
|
|
||||||
//constexpr ALWAYS_INLINE decltype(auto) SetContiguousAllowed(bool en) { this->SetBit(55, !en); return *this; }
|
|
||||||
constexpr ALWAYS_INLINE decltype(auto) SetUserExecuteNever(bool en) { this->SetBit(54, en); return *this; }
|
constexpr ALWAYS_INLINE decltype(auto) SetUserExecuteNever(bool en) { this->SetBit(54, en); return *this; }
|
||||||
constexpr ALWAYS_INLINE decltype(auto) SetPrivilegedExecuteNever(bool en) { this->SetBit(53, en); return *this; }
|
constexpr ALWAYS_INLINE decltype(auto) SetPrivilegedExecuteNever(bool en) { this->SetBit(53, en); return *this; }
|
||||||
constexpr ALWAYS_INLINE decltype(auto) SetContiguous(bool en) { this->SetBit(52, en); return *this; }
|
constexpr ALWAYS_INLINE decltype(auto) SetContiguous(bool en) { this->SetBit(52, en); return *this; }
|
||||||
|
|
|
@ -22,39 +22,40 @@ namespace ams::kern {
|
||||||
|
|
||||||
class KMemoryBlockManagerUpdateAllocator {
|
class KMemoryBlockManagerUpdateAllocator {
|
||||||
public:
|
public:
|
||||||
static constexpr size_t NumBlocks = 2;
|
static constexpr size_t MaxBlocks = 2;
|
||||||
private:
|
private:
|
||||||
KMemoryBlock *blocks[NumBlocks];
|
KMemoryBlock *blocks[MaxBlocks];
|
||||||
size_t index;
|
size_t index;
|
||||||
KMemoryBlockSlabManager *slab_manager;
|
KMemoryBlockSlabManager *slab_manager;
|
||||||
Result result;
|
|
||||||
public:
|
public:
|
||||||
explicit KMemoryBlockManagerUpdateAllocator(KMemoryBlockSlabManager *sm) : blocks(), index(), slab_manager(sm), result(svc::ResultOutOfResource()) {
|
constexpr explicit KMemoryBlockManagerUpdateAllocator(KMemoryBlockSlabManager *sm) : blocks(), index(MaxBlocks), slab_manager(sm) { /* ... */ }
|
||||||
for (size_t i = 0; i < NumBlocks; i++) {
|
|
||||||
this->blocks[i] = this->slab_manager->Allocate();
|
|
||||||
if (this->blocks[i] == nullptr) {
|
|
||||||
this->result = svc::ResultOutOfResource();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->result = ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
~KMemoryBlockManagerUpdateAllocator() {
|
~KMemoryBlockManagerUpdateAllocator() {
|
||||||
for (size_t i = 0; i < NumBlocks; i++) {
|
for (const auto &block : this->blocks) {
|
||||||
if (this->blocks[i] != nullptr) {
|
if (block != nullptr) {
|
||||||
this->slab_manager->Free(this->blocks[i]);
|
this->slab_manager->Free(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetResult() const {
|
Result Initialize(size_t num_blocks) {
|
||||||
return this->result;
|
/* Check num blocks. */
|
||||||
|
MESOSPHERE_ASSERT(num_blocks <= MaxBlocks);
|
||||||
|
|
||||||
|
/* Set index. */
|
||||||
|
this->index = MaxBlocks - num_blocks;
|
||||||
|
|
||||||
|
/* Allocate the blocks. */
|
||||||
|
for (size_t i = 0; i < num_blocks && i < MaxBlocks; ++i) {
|
||||||
|
this->blocks[this->index + i] = this->slab_manager->Allocate();
|
||||||
|
R_UNLESS(this->blocks[this->index + i] != nullptr, svc::ResultOutOfResource());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
KMemoryBlock *Allocate() {
|
KMemoryBlock *Allocate() {
|
||||||
MESOSPHERE_ABORT_UNLESS(this->index < NumBlocks);
|
MESOSPHERE_ABORT_UNLESS(this->index < MaxBlocks);
|
||||||
MESOSPHERE_ABORT_UNLESS(this->blocks[this->index] != nullptr);
|
MESOSPHERE_ABORT_UNLESS(this->blocks[this->index] != nullptr);
|
||||||
KMemoryBlock *block = nullptr;
|
KMemoryBlock *block = nullptr;
|
||||||
std::swap(block, this->blocks[this->index++]);
|
std::swap(block, this->blocks[this->index++]);
|
||||||
|
@ -62,7 +63,7 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Free(KMemoryBlock *block) {
|
void Free(KMemoryBlock *block) {
|
||||||
MESOSPHERE_ABORT_UNLESS(this->index <= NumBlocks);
|
MESOSPHERE_ABORT_UNLESS(this->index <= MaxBlocks);
|
||||||
MESOSPHERE_ABORT_UNLESS(block != nullptr);
|
MESOSPHERE_ABORT_UNLESS(block != nullptr);
|
||||||
if (this->index == 0) {
|
if (this->index == 0) {
|
||||||
this->slab_manager->Free(block);
|
this->slab_manager->Free(block);
|
||||||
|
|
|
@ -266,12 +266,18 @@ namespace ams::kern {
|
||||||
constexpr size_t GetNumGuardPages() const { return this->IsKernel() ? 1 : 4; }
|
constexpr size_t GetNumGuardPages() const { return this->IsKernel() ? 1 : 4; }
|
||||||
ALWAYS_INLINE KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const;
|
ALWAYS_INLINE KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, size_t guard_pages) const;
|
||||||
|
|
||||||
Result CheckMemoryStateContiguous(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const;
|
Result CheckMemoryStateContiguous(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const;
|
||||||
|
Result CheckMemoryStateContiguous(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const {
|
||||||
|
return this->CheckMemoryStateContiguous(nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr);
|
||||||
|
}
|
||||||
|
|
||||||
Result CheckMemoryState(const KMemoryInfo &info, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const;
|
Result CheckMemoryState(const KMemoryInfo &info, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const;
|
||||||
Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const;
|
Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||||
|
Result CheckMemoryState(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||||
|
return this->CheckMemoryState(nullptr, nullptr, nullptr, out_blocks_needed, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr);
|
||||||
|
}
|
||||||
Result CheckMemoryState(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const {
|
Result CheckMemoryState(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||||
return this->CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr);
|
return this->CheckMemoryState(nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LockMemoryAndOpen(KPageGroup *out_pg, KPhysicalAddress *out_paddr, 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);
|
Result LockMemoryAndOpen(KPageGroup *out_pg, KPhysicalAddress *out_paddr, 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);
|
||||||
|
@ -291,7 +297,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
NOINLINE Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
|
NOINLINE Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
|
||||||
|
|
||||||
Result SetupForIpcClient(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
|
Result SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
|
||||||
Result SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send);
|
Result SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send);
|
||||||
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission prot_perm);
|
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission prot_perm);
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -918,7 +918,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
if (!check_entry->IsForMerge(entry_template | GetInteger(phys_addr + L3BlockSize * i) | PageTableEntry::Type_L3Block)) {
|
if (!check_entry->IsForMerge(entry_template | GetInteger(phys_addr + L3BlockSize * i) | PageTableEntry::Type_L3Block)) {
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
if (i > 0 && (check_entry->IsHeadMergeDisabled() || check_entry->IsHeadAndBodyMergeDisabled())) {
|
if (i > 0 && (check_entry->IsHeadOrHeadAndBodyMergeDisabled())) {
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
if ((i < (L3ContiguousBlockSize / L3BlockSize) - 1) && check_entry->IsTailMergeDisabled()) {
|
if ((i < (L3ContiguousBlockSize / L3BlockSize) - 1) && check_entry->IsTailMergeDisabled()) {
|
||||||
|
@ -953,7 +953,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
if (!check_entry->IsForMerge(entry_template | GetInteger(phys_addr + L3ContiguousBlockSize * i) | PageTableEntry::ContigType_Contiguous | PageTableEntry::Type_L3Block)) {
|
if (!check_entry->IsForMerge(entry_template | GetInteger(phys_addr + L3ContiguousBlockSize * i) | PageTableEntry::ContigType_Contiguous | PageTableEntry::Type_L3Block)) {
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
if (i > 0 && (check_entry->IsHeadMergeDisabled() || check_entry->IsHeadAndBodyMergeDisabled())) {
|
if (i > 0 && (check_entry->IsHeadOrHeadAndBodyMergeDisabled())) {
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
if ((i < (L2BlockSize / L3ContiguousBlockSize) - 1) && check_entry->IsTailMergeDisabled()) {
|
if ((i < (L2BlockSize / L3ContiguousBlockSize) - 1) && check_entry->IsTailMergeDisabled()) {
|
||||||
|
@ -1000,7 +1000,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
if (!check_entry->IsForMerge(entry_template | GetInteger(phys_addr + L2BlockSize * i) | PageTableEntry::Type_L2Block)) {
|
if (!check_entry->IsForMerge(entry_template | GetInteger(phys_addr + L2BlockSize * i) | PageTableEntry::Type_L2Block)) {
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
if (i > 0 && (check_entry->IsHeadMergeDisabled() || check_entry->IsHeadAndBodyMergeDisabled())) {
|
if (i > 0 && (check_entry->IsHeadOrHeadAndBodyMergeDisabled())) {
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
if ((i < (L2ContiguousBlockSize / L2BlockSize) - 1) && check_entry->IsTailMergeDisabled()) {
|
if ((i < (L2ContiguousBlockSize / L2BlockSize) - 1) && check_entry->IsTailMergeDisabled()) {
|
||||||
|
@ -1035,7 +1035,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
if (!check_entry->IsForMerge(entry_template | GetInteger(phys_addr + L2ContiguousBlockSize * i) | PageTableEntry::ContigType_Contiguous | PageTableEntry::Type_L2Block)) {
|
if (!check_entry->IsForMerge(entry_template | GetInteger(phys_addr + L2ContiguousBlockSize * i) | PageTableEntry::ContigType_Contiguous | PageTableEntry::Type_L2Block)) {
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
if (i > 0 && (check_entry->IsHeadMergeDisabled() || check_entry->IsHeadAndBodyMergeDisabled())) {
|
if (i > 0 && (check_entry->IsHeadOrHeadAndBodyMergeDisabled())) {
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
if ((i < (L1ContiguousBlockSize / L2ContiguousBlockSize) - 1) && check_entry->IsTailMergeDisabled()) {
|
if ((i < (L1ContiguousBlockSize / L2ContiguousBlockSize) - 1) && check_entry->IsTailMergeDisabled()) {
|
||||||
|
|
|
@ -402,7 +402,7 @@ namespace ams::kern {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::CheckMemoryStateContiguous(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const {
|
Result KPageTableBase::CheckMemoryStateContiguous(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* Get information about the first block. */
|
/* Get information about the first block. */
|
||||||
|
@ -410,6 +410,9 @@ namespace ams::kern {
|
||||||
KMemoryBlockManager::const_iterator it = this->memory_block_manager.FindIterator(addr);
|
KMemoryBlockManager::const_iterator it = this->memory_block_manager.FindIterator(addr);
|
||||||
KMemoryInfo info = it->GetMemoryInfo();
|
KMemoryInfo info = it->GetMemoryInfo();
|
||||||
|
|
||||||
|
/* If the start address isn't aligned, we need a block. */
|
||||||
|
const size_t blocks_for_start_align = (util::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
/* Validate against the provided masks. */
|
/* Validate against the provided masks. */
|
||||||
R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
|
R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
|
||||||
|
@ -425,10 +428,17 @@ namespace ams::kern {
|
||||||
info = it->GetMemoryInfo();
|
info = it->GetMemoryInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the end address isn't aligned, we need a block. */
|
||||||
|
const size_t blocks_for_end_align = (util::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
|
||||||
|
|
||||||
|
if (out_blocks_needed != nullptr) {
|
||||||
|
*out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
|
||||||
|
}
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr) const {
|
Result KPageTableBase::CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr) const {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* Get information about the first block. */
|
/* Get information about the first block. */
|
||||||
|
@ -436,6 +446,9 @@ namespace ams::kern {
|
||||||
KMemoryBlockManager::const_iterator it = this->memory_block_manager.FindIterator(addr);
|
KMemoryBlockManager::const_iterator it = this->memory_block_manager.FindIterator(addr);
|
||||||
KMemoryInfo info = it->GetMemoryInfo();
|
KMemoryInfo info = it->GetMemoryInfo();
|
||||||
|
|
||||||
|
/* If the start address isn't aligned, we need a block. */
|
||||||
|
const size_t blocks_for_start_align = (util::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0;
|
||||||
|
|
||||||
/* Validate all blocks in the range have correct state. */
|
/* Validate all blocks in the range have correct state. */
|
||||||
const KMemoryState first_state = info.state;
|
const KMemoryState first_state = info.state;
|
||||||
const KMemoryPermission first_perm = info.perm;
|
const KMemoryPermission first_perm = info.perm;
|
||||||
|
@ -460,16 +473,22 @@ namespace ams::kern {
|
||||||
info = it->GetMemoryInfo();
|
info = it->GetMemoryInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the end address isn't aligned, we need a block. */
|
||||||
|
const size_t blocks_for_end_align = (util::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
|
||||||
|
|
||||||
/* Write output state. */
|
/* Write output state. */
|
||||||
if (out_state) {
|
if (out_state != nullptr) {
|
||||||
*out_state = first_state;
|
*out_state = first_state;
|
||||||
}
|
}
|
||||||
if (out_perm) {
|
if (out_perm != nullptr) {
|
||||||
*out_perm = first_perm;
|
*out_perm = first_perm;
|
||||||
}
|
}
|
||||||
if (out_attr) {
|
if (out_attr != nullptr) {
|
||||||
*out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr);
|
*out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr);
|
||||||
}
|
}
|
||||||
|
if (out_blocks_needed != nullptr) {
|
||||||
|
*out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
|
||||||
|
}
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,7 +513,8 @@ namespace ams::kern {
|
||||||
KMemoryState old_state;
|
KMemoryState old_state;
|
||||||
KMemoryPermission old_perm;
|
KMemoryPermission old_perm;
|
||||||
KMemoryAttribute old_attr;
|
KMemoryAttribute old_attr;
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), addr, size, state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks), addr, size, state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr));
|
||||||
|
|
||||||
/* Get the physical address, if we're supposed to. */
|
/* Get the physical address, if we're supposed to. */
|
||||||
if (out_paddr != nullptr) {
|
if (out_paddr != nullptr) {
|
||||||
|
@ -508,7 +528,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* Decide on new perm and attr. */
|
/* Decide on new perm and attr. */
|
||||||
new_perm = (new_perm != KMemoryPermission_None) ? new_perm : old_perm;
|
new_perm = (new_perm != KMemoryPermission_None) ? new_perm : old_perm;
|
||||||
|
@ -550,7 +570,8 @@ namespace ams::kern {
|
||||||
KMemoryState old_state;
|
KMemoryState old_state;
|
||||||
KMemoryPermission old_perm;
|
KMemoryPermission old_perm;
|
||||||
KMemoryAttribute old_attr;
|
KMemoryAttribute old_attr;
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), addr, size, state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks), addr, size, state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr));
|
||||||
|
|
||||||
/* Check the page group. */
|
/* Check the page group. */
|
||||||
if (pg != nullptr) {
|
if (pg != nullptr) {
|
||||||
|
@ -562,8 +583,10 @@ namespace ams::kern {
|
||||||
KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr & ~lock_attr);
|
KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(old_attr & ~lock_attr);
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
|
/* NOTE: Nintendo does not initialize the allocator with any blocks. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(0));
|
||||||
|
MESOSPHERE_UNUSED(num_allocator_blocks);
|
||||||
|
|
||||||
/* Update permission, if we need to. */
|
/* Update permission, if we need to. */
|
||||||
if (new_perm != old_perm) {
|
if (new_perm != old_perm) {
|
||||||
|
@ -669,18 +692,20 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Validate that the source address's state is valid. */
|
/* Validate that the source address's state is valid. */
|
||||||
KMemoryState src_state;
|
KMemoryState src_state;
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(src_state), nullptr, nullptr, src_address, size, KMemoryState_FlagCanAlias, KMemoryState_FlagCanAlias, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None));
|
size_t num_src_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(src_state), nullptr, nullptr, std::addressof(num_src_allocator_blocks), src_address, size, KMemoryState_FlagCanAlias, KMemoryState_FlagCanAlias, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Validate that the dst address's state is valid. */
|
/* Validate that the dst address's state is valid. */
|
||||||
R_TRY(this->CheckMemoryState(dst_address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
size_t num_dst_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Create an update allocator for the source. */
|
/* Create an update allocator for the source. */
|
||||||
KMemoryBlockManagerUpdateAllocator src_allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator src_allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(src_allocator.GetResult());
|
R_TRY(src_allocator.Initialize(num_src_allocator_blocks));
|
||||||
|
|
||||||
/* Create an update allocator for the destination. */
|
/* Create an update allocator for the destination. */
|
||||||
KMemoryBlockManagerUpdateAllocator dst_allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator dst_allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(dst_allocator.GetResult());
|
R_TRY(dst_allocator.Initialize(num_dst_allocator_blocks));
|
||||||
|
|
||||||
/* Map the memory. */
|
/* Map the memory. */
|
||||||
{
|
{
|
||||||
|
@ -729,19 +754,21 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Validate that the source address's state is valid. */
|
/* Validate that the source address's state is valid. */
|
||||||
KMemoryState src_state;
|
KMemoryState src_state;
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(src_state), nullptr, nullptr, src_address, size, KMemoryState_FlagCanAlias, KMemoryState_FlagCanAlias, KMemoryPermission_All, KMemoryPermission_NotMapped | KMemoryPermission_KernelRead, KMemoryAttribute_All, KMemoryAttribute_AnyLocked | KMemoryAttribute_Locked));
|
size_t num_src_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(src_state), nullptr, nullptr, std::addressof(num_src_allocator_blocks), src_address, size, KMemoryState_FlagCanAlias, KMemoryState_FlagCanAlias, KMemoryPermission_All, KMemoryPermission_NotMapped | KMemoryPermission_KernelRead, KMemoryAttribute_All, KMemoryAttribute_AnyLocked | KMemoryAttribute_Locked));
|
||||||
|
|
||||||
/* Validate that the dst address's state is valid. */
|
/* Validate that the dst address's state is valid. */
|
||||||
KMemoryPermission dst_perm;
|
KMemoryPermission dst_perm;
|
||||||
R_TRY(this->CheckMemoryState(nullptr, std::addressof(dst_perm), nullptr, dst_address, size, KMemoryState_All, KMemoryState_Stack, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
size_t num_dst_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(nullptr, std::addressof(dst_perm), nullptr, std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Stack, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Create an update allocator for the source. */
|
/* Create an update allocator for the source. */
|
||||||
KMemoryBlockManagerUpdateAllocator src_allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator src_allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(src_allocator.GetResult());
|
R_TRY(src_allocator.Initialize(num_src_allocator_blocks));
|
||||||
|
|
||||||
/* Create an update allocator for the destination. */
|
/* Create an update allocator for the destination. */
|
||||||
KMemoryBlockManagerUpdateAllocator dst_allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator dst_allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(dst_allocator.GetResult());
|
R_TRY(dst_allocator.Initialize(num_dst_allocator_blocks));
|
||||||
|
|
||||||
/* Unmap the memory. */
|
/* Unmap the memory. */
|
||||||
{
|
{
|
||||||
|
@ -794,18 +821,20 @@ namespace ams::kern {
|
||||||
/* Verify that the source memory is normal heap. */
|
/* Verify that the source memory is normal heap. */
|
||||||
KMemoryState src_state;
|
KMemoryState src_state;
|
||||||
KMemoryPermission src_perm;
|
KMemoryPermission src_perm;
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(src_state), std::addressof(src_perm), nullptr, src_address, size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None));
|
size_t num_src_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(src_state), std::addressof(src_perm), nullptr, std::addressof(num_src_allocator_blocks), src_address, size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Verify that the destination memory is unmapped. */
|
/* Verify that the destination memory is unmapped. */
|
||||||
R_TRY(this->CheckMemoryState(dst_address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
size_t num_dst_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Create an update allocator for the source. */
|
/* Create an update allocator for the source. */
|
||||||
KMemoryBlockManagerUpdateAllocator src_allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator src_allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(src_allocator.GetResult());
|
R_TRY(src_allocator.Initialize(num_src_allocator_blocks));
|
||||||
|
|
||||||
/* Create an update allocator for the destination. */
|
/* Create an update allocator for the destination. */
|
||||||
KMemoryBlockManagerUpdateAllocator dst_allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator dst_allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(dst_allocator.GetResult());
|
R_TRY(dst_allocator.Initialize(num_dst_allocator_blocks));
|
||||||
|
|
||||||
/* Map the code memory. */
|
/* Map the code memory. */
|
||||||
{
|
{
|
||||||
|
@ -855,10 +884,12 @@ namespace ams::kern {
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
/* Verify that the source memory is locked normal heap. */
|
/* Verify that the source memory is locked normal heap. */
|
||||||
R_TRY(this->CheckMemoryState(src_address, size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, static_cast<KMemoryAttribute>(KMemoryAttribute_AnyLocked | KMemoryAttribute_Locked)));
|
size_t num_src_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_src_allocator_blocks), src_address, size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, static_cast<KMemoryAttribute>(KMemoryAttribute_AnyLocked | KMemoryAttribute_Locked)));
|
||||||
|
|
||||||
/* Verify that the destination memory is aliasable code. */
|
/* Verify that the destination memory is aliasable code. */
|
||||||
R_TRY(this->CheckMemoryStateContiguous(dst_address, size, KMemoryState_FlagCanCodeAlias, KMemoryState_FlagCanCodeAlias, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
size_t num_dst_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryStateContiguous(std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState_FlagCanCodeAlias, KMemoryState_FlagCanCodeAlias, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Determine whether any pages being unmapped are code. */
|
/* Determine whether any pages being unmapped are code. */
|
||||||
bool any_code_pages = false;
|
bool any_code_pages = false;
|
||||||
|
@ -908,11 +939,11 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator for the source. */
|
/* Create an update allocator for the source. */
|
||||||
KMemoryBlockManagerUpdateAllocator src_allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator src_allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(src_allocator.GetResult());
|
R_TRY(src_allocator.Initialize(num_src_allocator_blocks));
|
||||||
|
|
||||||
/* Create an update allocator for the destination. */
|
/* Create an update allocator for the destination. */
|
||||||
KMemoryBlockManagerUpdateAllocator dst_allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator dst_allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(dst_allocator.GetResult());
|
R_TRY(dst_allocator.Initialize(num_dst_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1261,7 +1292,8 @@ namespace ams::kern {
|
||||||
/* Verify we can change the memory permission. */
|
/* Verify we can change the memory permission. */
|
||||||
KMemoryState old_state;
|
KMemoryState old_state;
|
||||||
KMemoryPermission old_perm;
|
KMemoryPermission old_perm;
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr, addr, size, KMemoryState_FlagCanReprotect, KMemoryState_FlagCanReprotect, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr, std::addressof(num_allocator_blocks), addr, size, KMemoryState_FlagCanReprotect, KMemoryState_FlagCanReprotect, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Determine new perm. */
|
/* Determine new perm. */
|
||||||
const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm);
|
const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm);
|
||||||
|
@ -1269,7 +1301,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1293,7 +1325,8 @@ namespace ams::kern {
|
||||||
/* Verify we can change the memory permission. */
|
/* Verify we can change the memory permission. */
|
||||||
KMemoryState old_state;
|
KMemoryState old_state;
|
||||||
KMemoryPermission old_perm;
|
KMemoryPermission old_perm;
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr, addr, size, KMemoryState_FlagCode, KMemoryState_FlagCode, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr, std::addressof(num_allocator_blocks), addr, size, KMemoryState_FlagCode, KMemoryState_FlagCode, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Make a new page group for the region. */
|
/* Make a new page group for the region. */
|
||||||
KPageGroup pg(this->block_info_manager);
|
KPageGroup pg(this->block_info_manager);
|
||||||
|
@ -1324,7 +1357,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1359,8 +1392,9 @@ namespace ams::kern {
|
||||||
KMemoryState old_state;
|
KMemoryState old_state;
|
||||||
KMemoryPermission old_perm;
|
KMemoryPermission old_perm;
|
||||||
KMemoryAttribute old_attr;
|
KMemoryAttribute old_attr;
|
||||||
|
size_t num_allocator_blocks;
|
||||||
constexpr u32 AttributeTestMask = ~(KMemoryAttribute_SetMask | KMemoryAttribute_DeviceShared);
|
constexpr u32 AttributeTestMask = ~(KMemoryAttribute_SetMask | KMemoryAttribute_DeviceShared);
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr),
|
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks),
|
||||||
addr, size,
|
addr, size,
|
||||||
KMemoryState_FlagCanChangeAttribute, KMemoryState_FlagCanChangeAttribute,
|
KMemoryState_FlagCanChangeAttribute, KMemoryState_FlagCanChangeAttribute,
|
||||||
KMemoryPermission_None, KMemoryPermission_None,
|
KMemoryPermission_None, KMemoryPermission_None,
|
||||||
|
@ -1368,7 +1402,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1405,19 +1439,21 @@ namespace ams::kern {
|
||||||
if (size < static_cast<size_t>(this->current_heap_end - this->heap_region_start)) {
|
if (size < static_cast<size_t>(this->current_heap_end - this->heap_region_start)) {
|
||||||
/* The size being requested is less than the current size, so we need to free the end of the heap. */
|
/* The size being requested is less than the current size, so we need to free the end of the heap. */
|
||||||
|
|
||||||
/* Create an update allocator. */
|
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
|
||||||
R_TRY(allocator.GetResult());
|
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
|
||||||
KScopedPageTableUpdater updater(this);
|
|
||||||
|
|
||||||
/* Validate memory state. */
|
/* Validate memory state. */
|
||||||
R_TRY(this->CheckMemoryState(this->heap_region_start + size, (this->current_heap_end - this->heap_region_start) - size,
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks),
|
||||||
|
this->heap_region_start + size, (this->current_heap_end - this->heap_region_start) - size,
|
||||||
KMemoryState_All, KMemoryState_Normal,
|
KMemoryState_All, KMemoryState_Normal,
|
||||||
KMemoryPermission_All, KMemoryPermission_UserReadWrite,
|
KMemoryPermission_All, KMemoryPermission_UserReadWrite,
|
||||||
KMemoryAttribute_All, KMemoryAttribute_None));
|
KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
|
/* Create an update allocator. */
|
||||||
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
|
/* We're going to perform an update, so create a helper. */
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
/* Unmap the end of the heap. */
|
/* Unmap the end of the heap. */
|
||||||
const size_t num_pages = ((this->current_heap_end - this->heap_region_start) - size) / PageSize;
|
const size_t num_pages = ((this->current_heap_end - this->heap_region_start) - size) / PageSize;
|
||||||
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
||||||
|
@ -1469,18 +1505,19 @@ namespace ams::kern {
|
||||||
/* Lock the table. */
|
/* Lock the table. */
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
/* Create an update allocator. */
|
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
|
||||||
R_TRY(allocator.GetResult());
|
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
|
||||||
KScopedPageTableUpdater updater(this);
|
|
||||||
|
|
||||||
/* Ensure that the heap hasn't changed since we began executing. */
|
/* Ensure that the heap hasn't changed since we began executing. */
|
||||||
MESOSPHERE_ABORT_UNLESS(cur_address == this->current_heap_end);
|
MESOSPHERE_ABORT_UNLESS(cur_address == this->current_heap_end);
|
||||||
|
|
||||||
/* Check the memory state. */
|
/* Check the memory state. */
|
||||||
R_TRY(this->CheckMemoryState(this->current_heap_end, allocation_size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), this->current_heap_end, allocation_size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||||
|
|
||||||
|
/* Create an update allocator. */
|
||||||
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
|
/* We're going to perform an update, so create a helper. */
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
/* Map the pages. */
|
/* Map the pages. */
|
||||||
const size_t num_pages = allocation_size / PageSize;
|
const size_t num_pages = allocation_size / PageSize;
|
||||||
|
@ -1677,7 +1714,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(KMemoryBlockManagerUpdateAllocator::MaxBlocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1744,7 +1781,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(KMemoryBlockManagerUpdateAllocator::MaxBlocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1792,7 +1829,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(KMemoryBlockManagerUpdateAllocator::MaxBlocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1822,11 +1859,12 @@ namespace ams::kern {
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
/* Check the memory state. */
|
/* Check the memory state. */
|
||||||
R_TRY(this->CheckMemoryState(address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1849,11 +1887,12 @@ namespace ams::kern {
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
/* Check the memory state. */
|
/* Check the memory state. */
|
||||||
R_TRY(this->CheckMemoryState(address, size, KMemoryState_All, state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1887,7 +1926,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(KMemoryBlockManagerUpdateAllocator::MaxBlocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1916,11 +1955,12 @@ namespace ams::kern {
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
/* Check if state allows us to map. */
|
/* Check if state allows us to map. */
|
||||||
R_TRY(this->CheckMemoryState(addr, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), addr, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -1948,14 +1988,15 @@ namespace ams::kern {
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
/* Check if state allows us to unmap. */
|
/* Check if state allows us to unmap. */
|
||||||
R_TRY(this->CheckMemoryState(address, size, KMemoryState_All, state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Check that the page group is valid. */
|
/* Check that the page group is valid. */
|
||||||
R_UNLESS(this->IsValidPageGroup(pg, address, num_pages), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(this->IsValidPageGroup(pg, address, num_pages), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -2263,7 +2304,8 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Check the memory state. */
|
/* Check the memory state. */
|
||||||
const u32 test_state = (is_aligned ? KMemoryState_FlagCanAlignedDeviceMap : KMemoryState_FlagCanDeviceMap);
|
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));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, test_state, test_state, perm, perm, KMemoryAttribute_AnyLocked | KMemoryAttribute_IpcLocked | KMemoryAttribute_Locked, 0, KMemoryAttribute_DeviceShared));
|
||||||
|
|
||||||
/* Make the page group, if we should. */
|
/* Make the page group, if we should. */
|
||||||
if (out != nullptr) {
|
if (out != nullptr) {
|
||||||
|
@ -2272,7 +2314,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* Update the memory blocks. */
|
/* Update the memory blocks. */
|
||||||
this->memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::ShareToDevice, KMemoryPermission_None);
|
this->memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::ShareToDevice, KMemoryPermission_None);
|
||||||
|
@ -2294,14 +2336,16 @@ namespace ams::kern {
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
/* Check the memory state. */
|
/* Check the memory state. */
|
||||||
R_TRY(this->CheckMemoryStateContiguous(address, size,
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryStateContiguous(std::addressof(num_allocator_blocks),
|
||||||
|
address, size,
|
||||||
KMemoryState_FlagCanDeviceMap, KMemoryState_FlagCanDeviceMap,
|
KMemoryState_FlagCanDeviceMap, KMemoryState_FlagCanDeviceMap,
|
||||||
KMemoryPermission_None, KMemoryPermission_None,
|
KMemoryPermission_None, KMemoryPermission_None,
|
||||||
KMemoryAttribute_AnyLocked | KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared));
|
KMemoryAttribute_AnyLocked | KMemoryAttribute_DeviceShared | KMemoryAttribute_Locked, KMemoryAttribute_DeviceShared));
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* Update the memory blocks. */
|
/* Update the memory blocks. */
|
||||||
this->memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::UnshareToDevice, KMemoryPermission_None);
|
this->memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::UnshareToDevice, KMemoryPermission_None);
|
||||||
|
@ -2917,7 +2961,7 @@ namespace ams::kern {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::SetupForIpcClient(PageLinkedList *page_list, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state) {
|
Result KPageTableBase::SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state) {
|
||||||
/* Validate pre-conditions. */
|
/* Validate pre-conditions. */
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
MESOSPHERE_ASSERT(test_perm == KMemoryPermission_UserReadWrite || test_perm == KMemoryPermission_UserRead);
|
MESOSPHERE_ASSERT(test_perm == KMemoryPermission_UserReadWrite || test_perm == KMemoryPermission_UserRead);
|
||||||
|
@ -2965,6 +3009,8 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
size_t blocks_needed = 0;
|
||||||
|
|
||||||
/* Iterate, mapping as needed. */
|
/* Iterate, mapping as needed. */
|
||||||
KMemoryBlockManager::const_iterator it = this->memory_block_manager.FindIterator(aligned_src_start);
|
KMemoryBlockManager::const_iterator it = this->memory_block_manager.FindIterator(aligned_src_start);
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -2975,9 +3021,16 @@ namespace ams::kern {
|
||||||
|
|
||||||
if (mapping_src_start < mapping_src_end && GetInteger(mapping_src_start) < info.GetEndAddress() && info.GetAddress() < GetInteger(mapping_src_end)) {
|
if (mapping_src_start < mapping_src_end && GetInteger(mapping_src_start) < info.GetEndAddress() && info.GetAddress() < GetInteger(mapping_src_end)) {
|
||||||
const auto cur_start = info.GetAddress() >= GetInteger(mapping_src_start) ? info.GetAddress() : GetInteger(mapping_src_start);
|
const auto cur_start = info.GetAddress() >= GetInteger(mapping_src_start) ? info.GetAddress() : GetInteger(mapping_src_start);
|
||||||
const auto cur_end = mapping_src_last <= info.GetLastAddress() ? GetInteger(mapping_src_end) : info.GetEndAddress();
|
const auto cur_end = mapping_src_last >= info.GetLastAddress() ? info.GetEndAddress() : GetInteger(mapping_src_end);
|
||||||
const size_t cur_size = cur_end - cur_start;
|
const size_t cur_size = cur_end - cur_start;
|
||||||
|
|
||||||
|
if (info.GetAddress() < GetInteger(mapping_src_start)) {
|
||||||
|
++blocks_needed;
|
||||||
|
}
|
||||||
|
if (mapping_src_last < info.GetLastAddress()) {
|
||||||
|
++blocks_needed;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the permissions on the block, if we need to. */
|
/* Set the permissions on the block, if we need to. */
|
||||||
if ((info.GetPermission() & KMemoryPermission_IpcLockChangeMask) != src_perm) {
|
if ((info.GetPermission() & KMemoryPermission_IpcLockChangeMask) != src_perm) {
|
||||||
const DisableMergeAttribute head_body_attr = (GetInteger(mapping_src_start) >= info.GetAddress()) ? DisableMergeAttribute_DisableHeadAndBody : DisableMergeAttribute_None;
|
const DisableMergeAttribute head_body_attr = (GetInteger(mapping_src_start) >= info.GetAddress()) ? DisableMergeAttribute_DisableHeadAndBody : DisableMergeAttribute_None;
|
||||||
|
@ -3003,6 +3056,11 @@ namespace ams::kern {
|
||||||
/* We succeeded, so no need to cleanup. */
|
/* We succeeded, so no need to cleanup. */
|
||||||
cleanup_guard.Cancel();
|
cleanup_guard.Cancel();
|
||||||
|
|
||||||
|
if (out_blocks_needed != nullptr) {
|
||||||
|
MESOSPHERE_ASSERT(blocks_needed <= KMemoryBlockManagerUpdateAllocator::MaxBlocks);
|
||||||
|
*out_blocks_needed = blocks_needed;
|
||||||
|
}
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3043,7 +3101,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(KMemoryBlockManagerUpdateAllocator::MaxBlocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -3231,15 +3289,16 @@ namespace ams::kern {
|
||||||
lk1.emplace(lock_1);
|
lk1.emplace(lock_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create an update allocator. */
|
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(src_page_table.memory_block_slab_manager);
|
|
||||||
R_TRY(allocator.GetResult());
|
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(std::addressof(src_page_table));
|
KScopedPageTableUpdater updater(std::addressof(src_page_table));
|
||||||
|
|
||||||
/* Perform client setup. */
|
/* Perform client setup. */
|
||||||
R_TRY(src_page_table.SetupForIpcClient(updater.GetPageList(), src_addr, size, test_perm, dst_state));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(src_page_table.SetupForIpcClient(updater.GetPageList(), std::addressof(num_allocator_blocks), src_addr, size, test_perm, dst_state));
|
||||||
|
|
||||||
|
/* Create an update allocator. */
|
||||||
|
KMemoryBlockManagerUpdateAllocator allocator(src_page_table.memory_block_slab_manager);
|
||||||
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* Get the mapped extents. */
|
/* Get the mapped extents. */
|
||||||
const KProcessAddress src_map_start = util::AlignUp(GetInteger(src_addr), PageSize);
|
const KProcessAddress src_map_start = util::AlignUp(GetInteger(src_addr), PageSize);
|
||||||
|
@ -3277,11 +3336,12 @@ namespace ams::kern {
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
/* Validate the memory state. */
|
/* Validate the memory state. */
|
||||||
R_TRY(this->CheckMemoryState(address, size, KMemoryState_All, dst_state, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_All, KMemoryAttribute_None));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, dst_state, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -3347,10 +3407,6 @@ namespace ams::kern {
|
||||||
/* NOTE: Nintendo does this *after* creating the updater below, but this does not follow convention elsewhere in KPageTableBase. */
|
/* NOTE: Nintendo does this *after* creating the updater below, but this does not follow convention elsewhere in KPageTableBase. */
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
/* Create an update allocator. */
|
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
|
||||||
R_TRY(allocator.GetResult());
|
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
|
@ -3485,6 +3541,11 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create an update allocator. */
|
||||||
|
/* NOTE: Guaranteed zero blocks needed here. */
|
||||||
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
|
R_TRY(allocator.Initialize(0));
|
||||||
|
|
||||||
/* Unlock the pages. */
|
/* Unlock the pages. */
|
||||||
this->memory_block_manager.UpdateLock(std::addressof(allocator), mapping_start, mapping_size / PageSize, &KMemoryBlock::UnlockForIpc, KMemoryPermission_None);
|
this->memory_block_manager.UpdateLock(std::addressof(allocator), mapping_start, mapping_size / PageSize, &KMemoryBlock::UnlockForIpc, KMemoryPermission_None);
|
||||||
|
|
||||||
|
@ -3566,7 +3627,6 @@ namespace ams::kern {
|
||||||
/* Lock the table. */
|
/* Lock the table. */
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
|
|
||||||
/* Iterate over the memory. */
|
/* Iterate over the memory. */
|
||||||
cur_address = address;
|
cur_address = address;
|
||||||
mapped_size = 0;
|
mapped_size = 0;
|
||||||
|
@ -3620,6 +3680,8 @@ namespace ams::kern {
|
||||||
/* Lock the table. */
|
/* Lock the table. */
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
|
size_t num_allocator_blocks = 0;
|
||||||
|
|
||||||
/* Verify that nobody has mapped memory since we first checked. */
|
/* Verify that nobody has mapped memory since we first checked. */
|
||||||
{
|
{
|
||||||
/* Iterate over the memory. */
|
/* Iterate over the memory. */
|
||||||
|
@ -3634,16 +3696,26 @@ namespace ams::kern {
|
||||||
/* Get the memory info. */
|
/* Get the memory info. */
|
||||||
const KMemoryInfo info = it->GetMemoryInfo();
|
const KMemoryInfo info = it->GetMemoryInfo();
|
||||||
|
|
||||||
|
const bool is_free = info.GetState() == KMemoryState_Free;
|
||||||
|
if (is_free) {
|
||||||
|
if (info.GetAddress() < GetInteger(address)) {
|
||||||
|
++num_allocator_blocks;
|
||||||
|
}
|
||||||
|
if (last_address < info.GetLastAddress()) {
|
||||||
|
++num_allocator_blocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we're done. */
|
/* Check if we're done. */
|
||||||
if (last_address <= info.GetLastAddress()) {
|
if (last_address <= info.GetLastAddress()) {
|
||||||
if (info.GetState() != KMemoryState_Free) {
|
if (!is_free) {
|
||||||
checked_mapped_size += (last_address + 1 - cur_address);
|
checked_mapped_size += (last_address + 1 - cur_address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Track the memory if it's mapped. */
|
/* Track the memory if it's mapped. */
|
||||||
if (info.GetState() != KMemoryState_Free) {
|
if (!is_free) {
|
||||||
checked_mapped_size += KProcessAddress(info.GetEndAddress()) - cur_address;
|
checked_mapped_size += KProcessAddress(info.GetEndAddress()) - cur_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3660,8 +3732,9 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
|
MESOSPHERE_ASSERT(num_allocator_blocks <= KMemoryBlockManagerUpdateAllocator::MaxBlocks);
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -3793,6 +3866,7 @@ namespace ams::kern {
|
||||||
/* Define iteration variables. */
|
/* Define iteration variables. */
|
||||||
KProcessAddress cur_address;
|
KProcessAddress cur_address;
|
||||||
size_t mapped_size;
|
size_t mapped_size;
|
||||||
|
size_t num_allocator_blocks = 0;
|
||||||
|
|
||||||
/* Check if the memory is mapped. */
|
/* Check if the memory is mapped. */
|
||||||
{
|
{
|
||||||
|
@ -3813,6 +3887,17 @@ namespace ams::kern {
|
||||||
const bool is_free = info.GetState() == KMemoryState_Free;
|
const bool is_free = info.GetState() == KMemoryState_Free;
|
||||||
R_UNLESS(is_normal || is_free, svc::ResultInvalidCurrentMemory());
|
R_UNLESS(is_normal || is_free, svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
if (is_normal) {
|
||||||
|
R_UNLESS(info.GetAttribute() == KMemoryAttribute_None, svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
if (info.GetAddress() < GetInteger(address)) {
|
||||||
|
++num_allocator_blocks;
|
||||||
|
}
|
||||||
|
if (last_address < info.GetLastAddress()) {
|
||||||
|
++num_allocator_blocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we're done. */
|
/* Check if we're done. */
|
||||||
if (last_address <= info.GetLastAddress()) {
|
if (last_address <= info.GetLastAddress()) {
|
||||||
if (is_normal) {
|
if (is_normal) {
|
||||||
|
@ -3884,8 +3969,9 @@ namespace ams::kern {
|
||||||
MESOSPHERE_ASSERT(pg.GetNumPages() == mapped_size / PageSize);
|
MESOSPHERE_ASSERT(pg.GetNumPages() == mapped_size / PageSize);
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
|
MESOSPHERE_ASSERT(num_allocator_blocks <= KMemoryBlockManagerUpdateAllocator::MaxBlocks);
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -4024,11 +4110,12 @@ namespace ams::kern {
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
/* Check the memory state. */
|
/* Check the memory state. */
|
||||||
R_TRY(this->CheckMemoryState(address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
@ -4057,11 +4144,12 @@ namespace ams::kern {
|
||||||
R_UNLESS(size <= this->mapped_unsafe_physical_memory, svc::ResultInvalidCurrentMemory());
|
R_UNLESS(size <= this->mapped_unsafe_physical_memory, svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Check the memory state. */
|
/* Check the memory state. */
|
||||||
R_TRY(this->CheckMemoryState(address, size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None));
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Create an update allocator. */
|
/* Create an update allocator. */
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
|
||||||
R_TRY(allocator.GetResult());
|
R_TRY(allocator.Initialize(num_allocator_blocks));
|
||||||
|
|
||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
Loading…
Reference in a new issue