Autor Thema: Paging und das ewige Problem mit der Rekursion (x86-64)  (Gelesen 6797 mal)

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« am: 14. February 2010, 13:36 »
Nun, ich hänge mal wieder beim Paging fest, das Problem ist folgendes:

Wenn eine neue Page gemappt werden soll, die dafür nötigen, höheren Level in der Pagingstruktur aber noch nicht vorhanden sind, werden diese zwar erstellt, müssen aber noch gemappt werden. Dies führt unweigerlich zu einer Rekursion und ich weiß einfach nicht, wie ich da raus komme.

void PagingManager::Map(uintptr_t virtual_address, uintptr_t physical_address)
{
this->UpdateIndexes(virtual_address & 0x000FFFFFFFFFF000LL);

PageMapLevel4Entry *pml4e = (PageMapLevel4Entry *)(page_map_level_4[pml4i].GetAddress());

if(pml4e->IsPresent() == false)
{
pml4e->Clear();
pml4e->SetAccess(PageAccess::UserWritable);
pml4e->SetAddress(memory.PAlloc());
pml4e->SetCachability(PageCachability::WriteThroughCachable);
pml4e->SetPresence(true);
}

PageDirectoryPointerEntry *pdpe = (PageDirectoryPointerEntry *)(pml4e[pdpi].GetAddress());

if(pdpe->IsPresent() == false)
{
pdpe->Clear();
pdpe->SetAccess(PageAccess::UserWritable);
pdpe->SetAddress(memory.PAlloc());
pdpe->SetCachability(PageCachability::WriteThroughCachable);
pdpe->SetPresence(true);
}

PageDirectoryEntry *pde = (PageDirectoryEntry *)(pdpe[pdi].GetAddress());

if(pde->IsPresent() == false)
{
pde->Clear();
pde->SetAccess(PageAccess::UserWritable);
pde->SetAddress(memory.PAlloc());
pde->SetCachability(PageCachability::WriteThroughCachable);
pde->SetPresence(true);
}

PageTableEntry *pte = (PageTableEntry *)(pde[pti].GetAddress());

pte->Clear();
pte->SetAccess(PageAccess::UserWritable);
pte->SetAddress(physical_address);
pte->SetCachability(PageCachability::WriteThroughCachable);
pte->SetPresence(true);
}
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #1 am: 14. February 2010, 14:25 »
Ich sehe in dem Quellcode keine Rekursion und ich kann mir auch nicht wirklich denken wo genau eine sein soll.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 14. February 2010, 14:31 »
Mein Fehler, dies ist noch der Code, der sich einfach verabschiedet (#PF), wenn die Level fehlen. Mit Rekursion wäre es dann:

void PagingManager::Map(uintptr_t virtual_address, uintptr_t physical_address)
{
this->UpdateIndexes(virtual_address & 0x000FFFFFFFFFF000LL);

PageMapLevel4Entry *pml4e = (PageMapLevel4Entry *)(page_map_level_4[pml4i].GetAddress());

if(pml4e->IsPresent() == false)
{
pml4e->Clear();
pml4e->SetAccess(PageAccess::UserWritable);
pml4e->SetAddress(memory.PAlloc());
pml4e->SetCachability(PageCachability::WriteThroughCachable);
pml4e->SetPresence(true);

this->Map(pml4e->GetAddress(), pml4e->GetAddress());
}

PageDirectoryPointerEntry *pdpe = (PageDirectoryPointerEntry *)(pml4e[pdpi].GetAddress());

if(pdpe->IsPresent() == false)
{
pdpe->Clear();
pdpe->SetAccess(PageAccess::UserWritable);
pdpe->SetAddress(memory.PAlloc());
pdpe->SetCachability(PageCachability::WriteThroughCachable);
pdpe->SetPresence(true);

this->Map(pdpe->GetAddress(), pdpe->GetAddress());
}

PageDirectoryEntry *pde = (PageDirectoryEntry *)(pdpe[pdi].GetAddress());

if(pde->IsPresent() == false)
{
pde->Clear();
pde->SetAccess(PageAccess::UserWritable);
pde->SetAddress(memory.PAlloc());
pde->SetCachability(PageCachability::WriteThroughCachable);
pde->SetPresence(true);

this->Map(pde->GetAddress(), pde->GetAddress());
}

PageTableEntry *pte = (PageTableEntry *)(pde[pti].GetAddress());

pte->Clear();
pte->SetAccess(PageAccess::UserWritable);
pte->SetAddress(physical_address);
pte->SetCachability(PageCachability::WriteThroughCachable);
pte->SetPresence(true);
}
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #3 am: 14. February 2010, 14:33 »
Wieso machst du nicht von Anfang an ein Identity Mapping des verfügbaren RAMs mit 2MiB Pages?
edit: Ansonsten gibts halt noch den Trick das PML4 als Page Directory irgendwo zu verwenden, dann sind auch alle Tabellen gemappt, zwar nicht identity, aber das brauchts ja eh nicht.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 14. February 2010, 14:36 »
Weil ich dann für jeden Task massig Speicher benötige, glaub ich. Ich müsste das trotzdem mal versuchen, sagt mir aber nicht so zu.
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #5 am: 14. February 2010, 14:41 »
Dafür brauchst du einmal Speicher, sicherlich nicht für jeden Task.

edit: Ich bin mir jetzt nicht 100% sicher, aber ich glaube es gibt auch 1GiB Pages.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 14. February 2010, 19:00 »
Jo, die gibt es, sind aber a) nicht auf jeder CPU verfügbar und b) sehr wenige. Ich versuche jetzt mit dem letzten 4 KiB Block (0xFFFFFFFFFFFFF000) immer das zu bearbeitende Element zu mappen, allerdings scheint es da noch ein wenig Probleme zu geben. Zur Zeit sieht das so aus:

void PagingManager::Map(uintptr_t virtual_address, uintptr_t physical_address)
{
this->UpdateIndexes(virtual_address & 0x000FFFFFFFFFF000LL);

this->dynamic_page->SetAddress(page_map_level_4[pml4i].GetAddress());

PageMapLevel4Entry *pml4e = (PageMapLevel4Entry *)(0xFFFFFFFFFFFFF000LL + pml4i * sizeof(PageMapLevel4Entry));

if(pml4e->IsPresent() == false)
{
pml4e->Clear();
pml4e->SetAccess(PageAccess::UserWritable);
pml4e->SetAddress(memory.PAlloc());
pml4e->SetCachability(PageCachability::WriteThroughCachable);
pml4e->SetPresence(true);

}

this->dynamic_page->SetAddress(pml4e[pdpi].GetAddress());

PageDirectoryPointerEntry *pdpe = (PageDirectoryPointerEntry *)(0xFFFFFFFFFFFFF000LL + pdpi * sizeof(PageMapLevel4Entry));

if(pdpe->IsPresent() == false)
{
pdpe->Clear();
pdpe->SetAccess(PageAccess::UserWritable);
pdpe->SetAddress(memory.PAlloc());
pdpe->SetCachability(PageCachability::WriteThroughCachable);
pdpe->SetPresence(true);
}

this->dynamic_page->SetAddress(pdpe[pdi].GetAddress());

PageDirectoryEntry *pde = (PageDirectoryEntry *)(0xFFFFFFFFFFFFF000LL + pdi * sizeof(PageDirectoryEntry));

pde->Clear();
pde->SetAccess(PageAccess::UserWritable);
pde->SetAddress(physical_address);
pde->SetCachability(PageCachability::WriteThroughCachable);
pde->SetPresence(true);
}
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 14. February 2010, 21:16 »
Jo, nimm das PML4 als PDPT, wenn das geht. Ist das einfachste, spart dir ständiges temporäres Ummappen und kostet nur virtuellen Speicher, den du sowieso in Massen hast.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 14. February 2010, 21:21 »
Du meinst rekursives Mapping wie im PM? Ist im LM nicht möglich, da sich die einzelnen Level in ihren Attributen unterscheiden :(
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 14. February 2010, 21:24 »
Hm, dann hat bluecode wohl Mist vorgeschlagen. ;)

Sind das kritische Attribute? Im PM unterscheiden sich PDE und PTE ja auch geringfügig, was man aber einfach ignorieren kann.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 14. February 2010, 22:06 »
Ja, im LM bestimmt z.B. Bit 7, ob das aktuelle Level das unterste ist (Nötig, da LM sowohl 1 GiB, 2 MiB und 4 KiB unterstützt).
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #11 am: 15. February 2010, 06:53 »
Hm, dann hat bluecode wohl Mist vorgeschlagen. ;)
Jop, hat er. :-D
SHyx0rmZ im IRC und ein Blick in die Manuals haben mich dann auch überzeugt, dass das nicht so toll tut.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 16. February 2010, 19:50 »
Auch wenn du den gesamten physischen Speicher nur mit 2 MiB Pages einfach irgendwohin mappst, brauchst du nur ein paar KB RAM für die PDPT.
« Letzte Änderung: 16. February 2010, 19:53 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

 

Einloggen