mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-14 00:56:35 +00:00
kern: add KPageGroup::CopyRangeTo
This commit is contained in:
parent
952188fc73
commit
6922eae3e7
3 changed files with 58 additions and 23 deletions
|
@ -145,6 +145,8 @@ namespace ams::kern {
|
|||
|
||||
bool IsEquivalentTo(const KPageGroup &rhs) const;
|
||||
|
||||
Result CopyRangeTo(KPageGroup &out, size_t offset, size_t size) const;
|
||||
|
||||
ALWAYS_INLINE bool operator==(const KPageGroup &rhs) const {
|
||||
return this->IsEquivalentTo(rhs);
|
||||
}
|
||||
|
|
|
@ -79,29 +79,7 @@ namespace ams::kern {
|
|||
|
||||
/* Create a page group representing the segment. */
|
||||
KPageGroup segment_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
||||
if (size_t remaining_size = util::AlignUp(seg_size, PageSize); remaining_size != 0) {
|
||||
/* Find the pages whose data corresponds to the segment. */
|
||||
size_t cur_offset = 0;
|
||||
for (auto it = pg.begin(); it != pg.end() && remaining_size > 0; ++it) {
|
||||
/* Get the current size. */
|
||||
const size_t cur_size = it->GetSize();
|
||||
|
||||
/* Determine if the offset is in range. */
|
||||
const size_t rel_diff = seg_offset - cur_offset;
|
||||
const bool is_before = cur_offset <= seg_offset;
|
||||
cur_offset += cur_size;
|
||||
if (is_before && seg_offset < cur_offset) {
|
||||
/* It is, so add the block. */
|
||||
const size_t block_size = std::min<size_t>(cur_size - rel_diff, remaining_size);
|
||||
MESOSPHERE_R_ABORT_UNLESS(segment_pg.AddBlock(it->GetAddress() + rel_diff, block_size / PageSize));
|
||||
|
||||
/* Advance. */
|
||||
cur_offset = seg_offset + block_size;
|
||||
remaining_size -= block_size;
|
||||
seg_offset += block_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
MESOSPHERE_R_ABORT_UNLESS(pg.CopyRangeTo(segment_pg, seg_offset, util::AlignUp(seg_size, PageSize)));
|
||||
|
||||
/* Setup the new page group's memory so that we can load the segment. */
|
||||
{
|
||||
|
@ -226,6 +204,9 @@ namespace ams::kern {
|
|||
const uintptr_t map_end = map_start + map_size;
|
||||
MESOSPHERE_ABORT_UNLESS(start_address == 0);
|
||||
|
||||
/* Default fields in parameter to zero. */
|
||||
*out = {};
|
||||
|
||||
/* Set fields in parameter. */
|
||||
out->code_address = map_start + start_address;
|
||||
out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize;
|
||||
|
|
|
@ -84,6 +84,58 @@ namespace ams::kern {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KPageGroup::CopyRangeTo(KPageGroup &out, size_t range_offset, size_t range_size) const {
|
||||
/* Get the previous last block for the group. */
|
||||
KBlockInfo * const out_last = out.m_last_block;
|
||||
const auto out_last_addr = out_last != nullptr ? out_last->GetAddress() : Null<KPhysicalAddress>;
|
||||
const auto out_last_np = out_last != nullptr ? out_last->GetNumPages() : 0;
|
||||
|
||||
/* Ensure we cleanup the group on failure. */
|
||||
ON_RESULT_FAILURE {
|
||||
KBlockInfo *cur = out_last != nullptr ? out_last->GetNext() : out.m_first_block;
|
||||
while (cur != nullptr) {
|
||||
KBlockInfo *next = cur->GetNext();
|
||||
out.m_manager->Free(cur);
|
||||
cur = next;
|
||||
}
|
||||
|
||||
if (out_last != nullptr) {
|
||||
out_last->Initialize(out_last_addr, out_last_np);
|
||||
out_last->SetNext(nullptr);
|
||||
} else {
|
||||
out.m_first_block = nullptr;
|
||||
}
|
||||
out.m_last_block = out_last;
|
||||
};
|
||||
|
||||
/* Find the pages within the requested range. */
|
||||
size_t cur_offset = 0, remaining_size = range_size;
|
||||
for (auto it = this->begin(); it != this->end() && remaining_size > 0; ++it) {
|
||||
/* Get the current size. */
|
||||
const size_t cur_size = it->GetSize();
|
||||
|
||||
/* Determine if the offset is in range. */
|
||||
const size_t rel_diff = range_offset - cur_offset;
|
||||
const bool is_before = cur_offset <= range_offset;
|
||||
cur_offset += cur_size;
|
||||
if (is_before && range_offset < cur_offset) {
|
||||
/* It is, so add the block. */
|
||||
const size_t block_size = std::min<size_t>(cur_size - rel_diff, remaining_size);
|
||||
R_TRY(out.AddBlock(it->GetAddress() + rel_diff, block_size / PageSize));
|
||||
|
||||
/* Advance. */
|
||||
cur_offset = range_offset + block_size;
|
||||
remaining_size -= block_size;
|
||||
range_offset += block_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that we successfully copied the range. */
|
||||
MESOSPHERE_ABORT_UNLESS(remaining_size == 0);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void KPageGroup::Open() const {
|
||||
auto &mm = Kernel::GetMemoryManager();
|
||||
|
||||
|
|
Loading…
Reference in a new issue