Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: Sapphire am 22. June 2008, 21:44
-
Hallo nachdem mir hier schon so schnell mit meiner memalloc Funktion geholfen wurde, habe ich wieder ein Problem an dem ich schon einige Zeit sitze.
Situation:
Ich lege erst ein PageDirectory und 2 PageTables an. Die erste Table mappt die ersten 4 MB Virtuellen Speicher auch in die ersten 4 MB der Physischen Speichers, und die 2te Mappt den Speicherbereich bei genau 3GB an 0xB8000 wo sich ja der Video speicher befindet.
Anschließend setze ich das Bit 31 in cr0 um Paging zu aktivieren.
Wenn ich jetz ganz normal auf die Adresse 0xB8000 zugreife geht alles gut nur wenn ich auf 0xC0000000 (3GB) zugreife bekomme ich eine Exception.
Problem:
Obwohl ich Bit 31 gesetzt habe ist es nicht gesetzt :-P wenn mein Interrupt Handler aufgerufen wird. Ich denke das er mir das Bit garnicht richtig setzt.
Frage:
Ist mein Code falsch (Code folgt unten) oder gibt es Fälle wo er das Bit einfach nicht setzten kann / bzw löscht der Prozessor das Bit 31 bei einer Exception automatisch ?
Wer net wenn mir da jemand Auskunft geben könnt.
Code:
Definition
struct Paging_PageDirectory
{
unsigned int PageTableAdress[1024];
};
struct Paging_PageTable
{
unsigned int PhysPageAdress[1024];
};
/*
Aktiviert Paging.
*/
void Paging_Enable( void );
/*
Deaktiviert Paging.
*/
void Paging_Disable( void );
/*
Ändert das aktive PageDirectory und
gibt die Adresse des Alten zurück
*/
void Paging_SwapDirectory( struct Paging_PageDirectory* Directory);
/*
Gibt das aktive PageDirectory zurück.
*/
struct Paging_PageDirectory* Paging_GetActivDirectoy( void );
/*
Erstellt ein PageDirectory an übergeben Adresse.
*/
struct Paging_PageDirectory* Paging_CreatePageDirectory( void* Adress);
/*
Fügt einen Eintrag im Angebeben PageDirectory hinzu und
erstellt eine PageTable an angebener Adresse.
*/
struct Paging_PageTable* Paging_AddPageDirectoryEntry(unsigned short Entry,void* PageTableAdress,struct Paging_PageDirectory* PagingDirectory);
/*
Gibt einen Eintrag aus einem PageDirectory zurück.
*/
struct Paging_PageTable* Paging_GetPageTable(struct Paging_PageDirectory* Directory,unsigned short Entry);
/*
Fügt einen Eintrag in eine PageTable hinzu.
*/
void Paging_AddPageTableEntry(struct Paging_PageDirectory* Directory,unsigned short DirectoryEntry,unsigned short TableEntry,void* PhysAdress);
Assembler Code
;C: void Paging_Enable( void );
_Paging_Enable:
push eax
mov eax,cr0 ;cr0 in eax laden
or eax,0x80000000 ;Bit Nr. 31 setzen
mov cr0,eax ;eax in cr0 schreiben
pop eax
ret ;zurück
;C: void Paging_Disable( void );
_Paging_Disable:
push eax
mov eax,cr0 ;cr0 in eax laden
xor eax,10000000000000000000000000000000b ;Bit Nr. 31 löschen
mov cr0,eax ;eax in cr0 schreiben
pop eax
ret
;C: void Paging_SwapDirectory( unsigned int DirectoryAdress );
_Paging_SwapDirectory: ; 1 Parameter: Adresse des neuen PageDirectory
push ebp
mov ebp, esp
push eax
mov eax, [ebp+8] ;Adresse nach eax lesen
mov cr3, eax
pop eax
mov esp, ebp
pop ebp
ret
;C: unsigned int Paging_GetActivDirectoy( void );
_Paging_GetActivDirectory:
mov eax,cr3 ;cr3 in eax laden
ret ;zurück (eax = Adresse)
C Code
/*
Erstellt ein PageDirectory an übergeben Adresse.
*/
struct Paging_PageDirectory* Paging_CreatePageDirectory( void* Adress)
{
//Überprüfen ob gültige Adress
if((((unsigned int)Adress)&0xFFFFF000)!=((unsigned int)Adress))
{
KMSG("Invalid Page DIrectory Adress\n\r");
//1 Sekunde warten
timer_waitticks(100);
}
//
memset(Adress,0x00,4096);
return (struct Paging_PageDirectory*)Adress;
};
/*
Fügt einen Eintrag im Angebeben PageDirectory hinzu und
erstellt eine PageTable an angebener Adresse.
*/
struct Paging_PageTable* Paging_AddPageDirectoryEntry(unsigned short Entry,void* PageTableAdress,struct Paging_PageDirectory* PagingDirectory)
{
//In Directory Eintragen
PagingDirectory->PageTableAdress[Entry] = (((unsigned int)PageTableAdress) | 0x007);
//Paging Table mit 0 füllen
memset(PageTableAdress,0x00,4096);
//PageTable zurückgeben
return (struct Paging_PageTable*)PageTableAdress;
};
/*
Gibt einen Eintrag aus einem PageDirectory zurück.
*/
struct Paging_PageTable* Paging_GetPageTable(struct Paging_PageDirectory* Directory,unsigned short Entry)
{
return (struct Paging_PageTable*)((Directory->PageTableAdress[Entry]) ^ 0x007);
};
/*
Fügt einen Eintrag in eine PageTable hinzu.
*/
void Paging_AddPageTableEntry(struct Paging_PageDirectory* Directory,unsigned short DirectoryEntry,unsigned short TableEntry,void* PhysAdress)
{
struct Paging_PageTable* Table = Paging_GetPageTable(Directory,DirectoryEntry);
Table->PhysPageAdress[TableEntry] = (((unsigned int)PhysAdress) | 0x007);
};
Initialisierung und Test:
struct Paging_PageDirectory* Directory = Paging_CreatePageDirectory(highmem_alloc());
Paging_AddPageDirectoryEntry(0,highmem_alloc(),Directory);
Paging_AddPageDirectoryEntry(768,highmem_alloc(),Directory);
//die Ersten 4 MB
int i=0;
unsigned int Phys = 0x00000000;
for(;i<1024;i++)
{
Paging_AddPageTableEntry(Directory,0,i,(void*)Phys);
Phys += 0x1000;
};
//3GB Erste Page
Paging_AddPageTableEntry(Directory,768,0,(void*)0xB8000);
Paging_SwapDirectory(Directory);
Paging_Enable();
KMSG("Paging Enabled!");
timer_waitticks(200);
char* Mem = 0xC0000000; //3 GB
char* String = "Test... Dies ist an die 3 GB Grenze geschrieben!";
for(i=0;i<strlen(String);i++)
{
*Mem = *String;
Mem++;
*Mem = KVC_White;
Mem++;
}
-
[...]gibt es Fälle wo er das Bit einfach nicht setzten kann / bzw löscht der Prozessor das Bit 31 bei einer Exception automatisch ?
Nein.
Gibt dein highmem_alloc Bereiche zurück die ein Alignment von 4kB haben (ein Page Directory/Table braucht ein 4kB align).
Was sagt denn bochs so generell? Irgendwelche anderen Exceptions? Sehen die Register sinnvoll aus?
Ich geh jetzt erstmal ins Bett. Ich werd mir evtl. morgen früh oder Nachmittag das ganze nochmal ansehen.
-
Bin grade noch in der Schule deswegen folgt der Wert der Register später.
Also Die Pagetables und das PageDirectory liegen auf jeden Fall in Bereichen die ein Alignment von 4kB haben. Das habe ich schon getestet.
Ich benutze leider Virtual PC bzw. VirtualBox, da Bochs bei bei mir leider schon am Anfang nicht richtig funktioniert hat, ... dass heißt es leif auf Bochs aber nicht auf richtigen PCs deswegen dachte ich mir das es so ja wenig Sinn macht, wenn das ganz dann nur auf Bochs läuft.
Sobald ich zuhause bin werde ich mal den Wert der Register posten.
Ich bin mir auch nicht so sicher ob die Werte die ich für cr0 und cr3 erhalte richtig sind, da ihc dort mit gcc inline assembler arbeite und mir das noch weniger vertraut ist als die Syntax von NASM.
[EDIT]
Also als Registerwerte bekomme ich folgendes bei Bochs, VirtualPC und VirtualBox:
GS:0x00000010
FS:0x00000010
ES:0x00000010
DS:0x00000010
EDI:0x00004000
ESI:0x000001FE
EBP:0x00105F20
ESP:0x00105EF4
EBX:0xFFFFFFFF
EDX:0xFFFFFFF4
ECX:0x00000001
EAX:0x00000000
EIP:0x001010F4
CS:0x00000008
EFLAGS:0x00010046
USERESP:0x00105F28
SS:0x001010F3
CR0:0x000B8000
CR3:0x000B8000
Ich denke das es bei den Werten von CR0 und CR3 wohl an meinem inline Assembler liegt, also poste ich auch mal den Code davon:
__asm__ ( "movl %%eax, %%cr0\n"
"push %%eax\n"
"call _PrintUIAsHex":::"%eax");
__asm__ ( "movl %eax, %cr3\n"
"push %eax\n"
"call _PrintUIAsHex":::"%eax");
[/EDIT]
-
Was für eine Exception tritt denn auf? GeneralProtection(13) oder Paging(14)? bei letzterem wäre interressant ob cr2 wirklich 0xc0000000 enthält.
@_Paging_Disable & Paging_GetPageTable
xor löscht keine bits sondern dreht sie um
@Paging_CreatePageDirectory
bei falscher Adresse wartest du 1sec und machst dann ganz normal weiter?
-
Stimmt, ist mir noch garnicht aufgefallen das ich dort weitermache, bei mir kam aber auch noch nie die Meldung "Invalid Page Directory Adress", also kann es daran nicht liegen.
Danke für den Hinweis mit dem xor.
[EDIT]
Also laut diesem "Artikel" http://www.oreilly.de/catalog/cplus2ger/chapter/ch11.pdf ist xor genau richtig! Oder verstehe ich da jetz was falsch?
[/EDIT]
Hmm also bei mir ist es Interrupt 15 (Coprocessor Fault).
-
als mit deinem Inline-ASM machst du dier den stack ganzschön kaput
und dann musst du beim AT&T-Syntax ziel und quelle immer vertauschen sprich
mov %cr0, %eax
aber du hast doch zumindest Paging_GetActivDirectory weshalb du dafür schon mal kein inline-ASM bräuchtest.
@bitmanipulation
wie du tabelle 11-5 entnehmen kannst gilt zwar
1 xor 1 = 0
aber dann musst du dir auch 1000% sicher sein dass du nicht so was hast
0 xor 1 = 1
deshalb solltest du zum löschen von bits immer and nehmen
1 and 0 = 0
0 and 0 = 0
1 and 1 = 1
0 and 1 = 0
zum löschen von bit 31: and 0x7fffffff
zum löschen von allen flags: and 0xfffff000
-
Du solltest dir dann vielleich den Wikiartikel (http://lowlevel.brainsware.org/wiki/index.php/Inline-Assembler_mit_GCC) zum GCC inline Assembler anschauen und speziell was die Eingabe/Ausgabeliste bei den asm Statements ist und wie man sie sinnvoll beim Lesen/Schreiben von speziellen Prozessorregistern verwenden kann. Beispielcode gibts dazu auch im Hobby-OS deiner Wahl.
btw. was im Wiki verwunderlicherweise nicht steht ist, dass man asm volatile nutzen sollte (zumindest schadet es in keinem Fall, wobei wenn man nur das asm hat man evtl. große und schwer zu debuggende Probleme kriegen kann).
-
Danke @ MNemo für die aufklärung über AND und XOR. Mit Bitoperatoren hatte ich noch nicht sehr viel zu tun ... .
Also ich habe jetzt noch eine Funktion für das auslesen des CR0 Registers.
Die Werte von CR0 und CR3 sind:
CR0: 0xE0000011
CR3: 0x00005000
Da der Wert von CR3 auf keinen Fall stimmen kann da der von mir angeforderte Speicher erst bei 16 MB beginnt, habe ich mir die Funktion Paging_SwapDirectory nocheinmal angeguckt.
Dabei sidn mir 2 Dinge aufgefallen:
1.
Ich bin mir nicht sicher ob man die Parameter mit mov vom Stack nehmen sollte.
Werden die Werte nicht so nur kopiert und der Stack dadurch auch zerstört?
2.
Ich dachte mir es muss "ebp+12" und nicht "ebp+8" heißen?
Als ich es ausprobiert habe, hat es nicht mal mehr einen Interrupt gegeben:
VirtualPC hat Windows zu einem Bluescreen gebracht, VirtualBox macht einige Zeit nichts und schaltet sich dann mit einem internen Fehler ab, und Bochs startet andauernt neu.
PS: Meine Speicherfunktion funktioniert richtig. Ich habe mir vorher schonmal die Adresse die es zurückliefert angeguckt. Die ist korrekt.
-
Die Funktion _Paging_SwapDirectory ist völlig korrekt. An [EBP] liegt der alte EBP Wert, an [EBP + 4] liegt die return-Adresse und an [EBP + 8] liegt das erste Argument. Auch die mov-Instruction ist richtig, du möchtest schließlich das Argument lesen und nicht vom Stack nehmen. (Vom Stack genommen wird es bei Verwendung von gccs Standard Calling Convention vom Caller.)
EDIT: Argh, dieser Post war auf die ursprünglichen Funktionen bezogen. Deine Inline Funktion die oben stehen sind fehlerhaft. Beachte Bluecodes Hinweis und poste deine geänderten Inline Assembler Zeilen nochmal.
-
Ok Ich habe jetz alles nocheinmal neu compiliert und jetz wird der Wert des cr3 Register richtig angegeben ( der gleiche wie die Adresse des PageDirectory) .
EDIT: @ Korona: Ich benutze auch die Ursprüngliche Funktion jetzt auch. Mein letzter Post war da vll ein wenig(...) zu undeutlich.
Aber ich bekomme immernoch eine "Coprocessor Fault Exiption" (Bei mir Interrupt 14 ! Ist das so richtig?)
Also müsste das PageDirectory bzw die PageTables nicht richtig erstellt werden.
Ich werde mir das ganze nochmal angucken und die Lösung posten wenn ich sie finde.
Danke schonmal für die Hilfe bis jetzt, wenn ich den Fehler nicht finde werde ich mich nochmal melden.
-
Interrupt 14 ist der Page-Fault siehe hier (http://www.fh-zwickau.de/doc/prmo/pmtutor/text/exc.htm)
da wäre jetzt das CR2 register interresant, das enthält die Adresse die die Exception ausgelöst hat.
-
Also das CR2 Register enthält den Wert 0x001023C3, was ja bedeuten würde das die erste Page nicht richtig erstellt wurde oder ?
EDIT:
Da kann doch i-etwas nicht oder ? wenn der Fehler in der ersten page liegt könnte ich danach doch garnicht mehr KMSG aufrufen oder ? Das klappt ja aber noch!
-
Ich benutze leider Virtual PC bzw. VirtualBox, da Bochs bei bei mir leider schon am Anfang nicht richtig funktioniert hat, ... dass heißt es leif auf Bochs aber nicht auf richtigen PCs deswegen dachte ich mir das es so ja wenig Sinn macht, wenn das ganz dann nur auf Bochs läuft.
Teste auf so vielen Emulatoren/PCs so oft wie möglich. Sobald ein Fehler auch auf einem Emulator auftritt, würde ich den dort debuggen, denn auf einem echten PC debuggen ist zeitaufwändig (wegen neustarts) und ist auch weit einfacher, wegen der erweiterten Möglichkeiten, die bochs & qemu bieten.
Bei welcher Instruktion page-faultet es denn überhaupt? Mit bochs & qemu (bei letzerem noch ein Kommandozeilenflag angeben, dann schreibt er dir auftretende Interrupts/Exceptions in eine Logdatei) einfach laufen lassen und dann im Log schauen, wo eip ist vor der Exception. Danach deine Binary disassemblieren und schauen in welcher Funktion und bei welchem Statement es ungefähr page-faultet. Cr2 widerspricht nämlich irgendwie deiner These, dass es beim Zugriff auf 0xC0000000 schief geht...
-
um mir das disassemblieren zu ersparen lass ich den linker einfach ne memorymap erstellen "ld -Map datei ..." dann weiß man zwar nicht ganzgenau wo der fehler ist, aber in welcher funktion er steckt findet man raus.
BTW: wie disassembliert man ELF dateien? mit ndisasm gehts nicht.
[edit] hat sich erledigt ( objdump ) [/edit]
-
Also bei mir geht das alles nícht so ... leider... .
QEMU will bei mir einfach nicht laufen. Entweder findet er eine Datei von KQEMU nicht, und wenn ich KQEMU dann installiere findet er eine andere wieder nicht.
Und bei Bochs bin ich einfach zu blöd mit diesem step xxx die richtige stelle zu treffen. Hab dort schon einen Watchpoint angelegt der mir melden soll wenn auf 0x001023C3 zugegriffen wird, aber das klappt auch nicht. Weiß jemand wie man dort noch weiter kommen könnte ?
Sonst muss ich mich wohl nochmal an qemu versuchen.
[EDIT]
Auf jeden Fall habt ihr Recht das es nicht hier ran liegt:
char* Mem = 0xC0000000; //3 GB
char* String = "Test... Dies ist an die 3 GB Grenze geschrieben!";
for(i=0;i<strlen(String);i++)
{
*Mem = *String;
Mem++;
*Mem = KVC_White;
Mem++;
}
Wenn ich diesen Teil weglasse bekomme ich auch eine Page-Fault, jedoch an Adresse 0x00102363.
Kann sich das jemand erklären ? Vielleicht wird ein Teil der ersten Map nicht richtig erstellt, das mein Code an der for-Schleife anschließend eine Page-Fault auslöst.
Wenn ich mir meine Disassembli (?) so ansehe ist in _main auch keine Schleife am Ende. könnte es sein das der Compiler die leere for-Fchleife einfach ignoriert ?
Disassembli
_main proc near ; CODE XREF: seg000:0000002Dp
seg000:000002D1
seg000:000002D1 var_30 = dword ptr -30h
seg000:000002D1 var_C = byte ptr -0Ch
seg000:000002D1 arg_0 = byte ptr 4
seg000:000002D1
seg000:000002D1 lea ecx, [esp+arg_0]
seg000:000002D5 and esp, 0FFFFFFF0h
seg000:000002D8 push dword ptr [ecx-4]
seg000:000002DB push ebp
seg000:000002DC mov ebp, esp
seg000:000002DE push esi
seg000:000002DF push ebx
seg000:000002E0 push ecx
seg000:000002E1 sub esp, 18h
seg000:000002E4 mov ebx, [ecx]
seg000:000002E6 push 0
seg000:000002E8 call sub_EF0
seg000:000002ED call sub_283
seg000:000002F2 call sub_1730
seg000:000002F7 pop eax
seg000:000002F8 mov eax, [ebx+4]
seg000:000002FB pop edx
seg000:000002FC add eax, [ebx+8]
seg000:000002FF sub eax, 1000000h
seg000:00000304 push eax
seg000:00000305 push 1000000h
seg000:0000030A call sub_17B0
seg000:0000030F call sub_1805
seg000:00000314 add esp, 10h
seg000:00000317 test eax, eax
seg000:00000319 jnz short loc_334
seg000:0000031B push eax
seg000:0000031C push eax
seg000:0000031D push 0Fh
seg000:0000031F push 1002A5h
seg000:00000324 call sub_FD8
seg000:00000329 lea esp, [ebp-0Ch]
seg000:0000032C pop ecx
seg000:0000032D pop ebx
seg000:0000032E pop esi
seg000:0000032F pop ebp
seg000:00000330 lea esp, [ecx-4]
seg000:00000333 retn
[/EDIT]
-
du kommst doch an das EIP, dann weißt du doch schon wo der fehler auftritt
du brauchs also nur noch gucken zu welcher funktion die adresse gehört.
aber dein _main disasembli passt auch irgend wie nicht zu deinem "Initialisierung und Tests" code.
@bochs
wenn ich das so richtig verstanden habe beziehen sich watchpoints auf physikalische adressen, nicht auf logische. passt also nicht zu deinem problem.
@qemu
wenn du unter win**** arbeitest must du glaub ich dem Qemu noch den parameter "-L <pfad zu bios.bin>" übergeben. KQemu braucht man eigentlich nicht.
-
Also hab jetz noch etwas rausgefunden:
An der for Schleife liegt es auch nicht.
Ich bae for der for-Schleife noch einen timer_waitticks eingebaut der 60 Sekunden warten soll.
Das heißt es muss irgendwo nachdem aktivieren das Paging passieren.
Fals jemand jetz noch ws weiß was habwegs nützlich sein könnte bitte einfach posten. Ich weiß wirklich ncih wo der Fehler liegen könnte.
-
Am besten zeigst du uns wohl mal den ganzen Code (als Archiv, so dass wir ihn kompilieren können). So finden wir den Fehler wohl am ehsten.
-
Also hier mein Source Dateien.
http://cid-f20ff61cbfb84ec7.skydrive.live.com/self.aspx/%c3%96ffentlich/Kernel.zip
Ich hoffe es hilft.
Kann mir villeicht jemand ne Seite empfehlen wo ich was über das Bebuggen mit Bochs finden kann ?
-
Kannst mal hier schauen: http://www.chris-soft.de/tutorials/bochs/
Gruss
Nooooooooooos
-
also der fehler tritt direct beim einschalten vom Paging ein.
und zwar gibt dein highmem_alloc() keinesfalls werte über 16MB aus, sonder werte wie 0x18000, das liegt möglicher weise daran das BootInfo->mem_{high,low} werte in KB angeben.
Vermutlich sollte es bei dir also so aussehen:
highmem_init(0x1000000, BootInformation->mem_high+BootInformation->mem_low)*1024-0x1000000);
[edit]
deine memset funktion hat nen fehler:
du benutzt edi sicherst aber das esi register
[/edit]
[edit]
deine GetCR2 funktio ist ne kopie von GetCR0
und der beim aufruf in der isrs.c solltest du noch ( ) dranhängen, du wilst ja nicht die adresse der funktion ausgeben, oder ;)
das behebt zwar noch nicht alle fehler, aber es sollte schon mal helfen die restlichen zu finden
[/edit]
-
Ok danke. Werde das ganze jetz mal Testen mit den Tips die ihr mir gegeben habt. Wenn ich selbst jetzt nichts mehr finde werde ich mcih nochmal melden.
[EDIT]
Die memset Funktion ist die hier aus dem Forum aus dem Resourcen Teil. Vll sollte die Dort auch berichtigt werden.
[/EDIT]
-
OK. Läuft nun alles.
Nach noch einem kleinen Fehler der mir eine Page-Fault bei 0xFFFFFFFF angezeigt hat, funktioniert nun alles.
(Wen es interesiert: Der Fehler liegt in der Timer-Funktion die jede Sekunde etwas auf den Bildschrim schreibt.)
Danke an alle nochmal.