Implement VMM region->region copies

Required by the DMA engine, a simple memcpy doesn't work since the buffers could span multiple blocks.
This commit is contained in:
Billy Laws 2022-04-09 12:14:10 +01:00 committed by PixelyIon
parent af90d4f977
commit 7717a86fb1
2 changed files with 64 additions and 0 deletions

View File

@ -197,6 +197,8 @@ namespace skyline {
void Write(VaType virt, T source) {
Write(virt, reinterpret_cast<u8 *>(&source), sizeof(T));
}
void Copy(VaType dst, VaType src, VaType size);
};
/**

View File

@ -342,7 +342,69 @@ namespace skyline {
blockWriteSize = std::min(successor->virt - predecessor->virt, size);
}
}
}
MM_MEMBER(void)::Copy(VaType dst, VaType src, VaType size) {
TRACE_EVENT("containers", "FlatMemoryManager::Copy");
std::scoped_lock lock(this->blockMutex);
VaType srcEnd{src + size};
VaType dstEnd{dst + size};
auto srcSuccessor{std::upper_bound(this->blocks.begin(), this->blocks.end(), src, [] (auto virt, const auto &block) {
return virt < block.virt;
})};
auto dstSuccessor{std::upper_bound(this->blocks.begin(), this->blocks.end(), dst, [] (auto virt, const auto &block) {
return virt < block.virt;
})};
auto srcPredecessor{std::prev(srcSuccessor)};
auto dstPredecessor{std::prev(dstSuccessor)};
u8 *srcBlockPhys{srcPredecessor->phys + (src - srcPredecessor->virt)};
u8 *dstBlockPhys{dstPredecessor->phys + (dst - dstPredecessor->virt)};
VaType srcBlockRemainingSize{srcSuccessor->virt - src};
VaType dstBlockRemainingSize{dstSuccessor->virt - dst};
VaType blockCopySize{std::min({srcBlockRemainingSize, dstBlockRemainingSize, size})};
// Writes may span across multiple individual blocks
while (size) {
if (srcPredecessor->phys == nullptr) {
throw exception("Page fault at 0x{:X}", srcPredecessor->virt);
} else if (dstPredecessor->phys == nullptr) {
throw exception("Page fault at 0x{:X}", dstPredecessor->virt);
} else { [[likely]]
if (srcPredecessor->extraInfo.sparseMapped)
std::memset(dstBlockPhys, 0, blockCopySize);
else [[likely]]
std::memcpy(dstBlockPhys, srcBlockPhys, blockCopySize);
}
dstBlockPhys += blockCopySize;
srcBlockPhys += blockCopySize;
size -= blockCopySize;
srcBlockRemainingSize -= blockCopySize;
dstBlockRemainingSize -= blockCopySize;
if (size) {
if (!srcBlockRemainingSize) {
srcPredecessor = srcSuccessor++;
srcBlockPhys = srcPredecessor->phys;
srcBlockRemainingSize = srcSuccessor->virt - srcPredecessor->virt;
blockCopySize = std::min({srcBlockRemainingSize, dstBlockRemainingSize, size});
}
if (!dstBlockRemainingSize) {
dstPredecessor = dstSuccessor++;
dstBlockPhys = dstPredecessor->phys;
dstBlockRemainingSize = dstSuccessor->virt - dstPredecessor->virt;
blockCopySize = std::min({srcBlockRemainingSize, dstBlockRemainingSize, size});
}
}
}
}
ALLOC_MEMBER()::FlatAllocator(VaType vaStart, VaType vaLimit) : Base(vaLimit), vaStart(vaStart), currentLinearAllocEnd(vaStart) {}