k_page_table: add MapFirstGroup

This commit is contained in:
Liam 2023-10-11 13:12:02 -04:00
parent b456af31e6
commit f21058a6c0
3 changed files with 48 additions and 33 deletions

View file

@ -183,12 +183,17 @@ private:
class KScopedPageGroup { class KScopedPageGroup {
public: public:
explicit KScopedPageGroup(const KPageGroup* gp) : m_pg(gp) { explicit KScopedPageGroup(const KPageGroup* gp, bool not_first = true) : m_pg(gp) {
if (m_pg) { if (m_pg) {
if (not_first) {
m_pg->Open(); m_pg->Open();
} else {
m_pg->OpenFirst();
} }
} }
explicit KScopedPageGroup(const KPageGroup& gp) : KScopedPageGroup(std::addressof(gp)) {} }
explicit KScopedPageGroup(const KPageGroup& gp, bool not_first = true)
: KScopedPageGroup(std::addressof(gp), not_first) {}
~KScopedPageGroup() { ~KScopedPageGroup() {
if (m_pg) { if (m_pg) {
m_pg->Close(); m_pg->Close();

View file

@ -1724,7 +1724,17 @@ Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) {
PageSize; PageSize;
// While we have pages to map, map them. // While we have pages to map, map them.
while (map_pages > 0) { {
// Create a page group for the current mapping range.
KPageGroup cur_pg(m_kernel, m_block_info_manager);
{
ON_RESULT_FAILURE_2 {
cur_pg.OpenFirst();
cur_pg.Close();
};
size_t remain_pages = map_pages;
while (remain_pages > 0) {
// Check if we're at the end of the physical block. // Check if we're at the end of the physical block.
if (pg_pages == 0) { if (pg_pages == 0) {
// Ensure there are more pages to map. // Ensure there are more pages to map.
@ -1736,20 +1746,24 @@ Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) {
pg_pages = pg_it->GetNumPages(); pg_pages = pg_it->GetNumPages();
} }
// Map whatever we can. // Add whatever we can to the current block.
const size_t cur_pages = std::min(pg_pages, map_pages); const size_t cur_pages = std::min(pg_pages, remain_pages);
R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::UserReadWrite, R_TRY(cur_pg.AddBlock(pg_phys_addr +
OperationType::MapFirst, pg_phys_addr)); ((pg_pages - cur_pages) * PageSize),
cur_pages));
// Advance. // Advance.
cur_address += cur_pages * PageSize; remain_pages -= cur_pages;
map_pages -= cur_pages;
pg_phys_addr += cur_pages * PageSize;
pg_pages -= cur_pages; pg_pages -= cur_pages;
} }
} }
// Map the pages.
R_TRY(this->Operate(cur_address, map_pages, cur_pg,
OperationType::MapFirstGroup));
}
}
// Check if we're done. // Check if we're done.
if (last_address <= info.GetLastAddress()) { if (last_address <= info.GetLastAddress()) {
break; break;
@ -3037,9 +3051,10 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, const KPageGr
ASSERT(num_pages == page_group.GetNumPages()); ASSERT(num_pages == page_group.GetNumPages());
switch (operation) { switch (operation) {
case OperationType::MapGroup: { case OperationType::MapGroup:
case OperationType::MapFirstGroup: {
// We want to maintain a new reference to every page in the group. // We want to maintain a new reference to every page in the group.
KScopedPageGroup spg(page_group); KScopedPageGroup spg(page_group, operation != OperationType::MapFirstGroup);
for (const auto& node : page_group) { for (const auto& node : page_group) {
const size_t size{node.GetNumPages() * PageSize}; const size_t size{node.GetNumPages() * PageSize};
@ -3081,7 +3096,6 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis
m_memory->UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize); m_memory->UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize);
break; break;
} }
case OperationType::MapFirst:
case OperationType::Map: { case OperationType::Map: {
ASSERT(map_addr); ASSERT(map_addr);
ASSERT(Common::IsAligned(GetInteger(map_addr), PageSize)); ASSERT(Common::IsAligned(GetInteger(map_addr), PageSize));
@ -3089,12 +3103,8 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis
// Open references to pages, if we should. // Open references to pages, if we should.
if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) { if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) {
if (operation == OperationType::MapFirst) {
m_kernel.MemoryManager().OpenFirst(map_addr, num_pages);
} else {
m_kernel.MemoryManager().Open(map_addr, num_pages); m_kernel.MemoryManager().Open(map_addr, num_pages);
} }
}
break; break;
} }
case OperationType::Separate: { case OperationType::Separate: {

View file

@ -217,8 +217,8 @@ protected:
private: private:
enum class OperationType : u32 { enum class OperationType : u32 {
Map = 0, Map = 0,
MapFirst = 1, MapGroup = 1,
MapGroup = 2, MapFirstGroup = 2,
Unmap = 3, Unmap = 3,
ChangePermissions = 4, ChangePermissions = 4,
ChangePermissionsAndRefresh = 5, ChangePermissionsAndRefresh = 5,