mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +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;
|
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 {
|
ALWAYS_INLINE bool operator==(const KPageGroup &rhs) const {
|
||||||
return this->IsEquivalentTo(rhs);
|
return this->IsEquivalentTo(rhs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,29 +79,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create a page group representing the segment. */
|
/* Create a page group representing the segment. */
|
||||||
KPageGroup segment_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
KPageGroup segment_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
||||||
if (size_t remaining_size = util::AlignUp(seg_size, PageSize); remaining_size != 0) {
|
MESOSPHERE_R_ABORT_UNLESS(pg.CopyRangeTo(segment_pg, seg_offset, util::AlignUp(seg_size, PageSize)));
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup the new page group's memory so that we can load the segment. */
|
/* 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;
|
const uintptr_t map_end = map_start + map_size;
|
||||||
MESOSPHERE_ABORT_UNLESS(start_address == 0);
|
MESOSPHERE_ABORT_UNLESS(start_address == 0);
|
||||||
|
|
||||||
|
/* Default fields in parameter to zero. */
|
||||||
|
*out = {};
|
||||||
|
|
||||||
/* Set fields in parameter. */
|
/* Set fields in parameter. */
|
||||||
out->code_address = map_start + start_address;
|
out->code_address = map_start + start_address;
|
||||||
out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize;
|
out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize;
|
||||||
|
|
|
@ -84,6 +84,58 @@ namespace ams::kern {
|
||||||
R_SUCCEED();
|
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 {
|
void KPageGroup::Open() const {
|
||||||
auto &mm = Kernel::GetMemoryManager();
|
auto &mm = Kernel::GetMemoryManager();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue