Beiträge anzeigen

Diese Sektion erlaubt es dir alle Beiträge dieses Mitglieds zu sehen. Beachte, dass du nur solche Beiträge sehen kannst, zu denen du auch Zugriffsrechte hast.


Nachrichten - Jidder

Seiten: 1 [2] 3 4 ... 81
21
Keine gesetzten unteren Bits heißt, dass es sich um einen Fehler mit Bezug auf die GDT handelt. Es wird also vermutlich versucht 0x400 in ein Segmentregister zu laden. (Meine vermutete Ursache ist wie immer ein beschädigter oder falscher Stack.)
22
Die gesetzen Flags in 0x213 sind das Direction Flag (0x200), das Auxilary Carry Flag (0x10) und das Carry Flag (0x1). Das Nested Task Flag ist 0x4000 und hier nicht gesetzt. Dass da Flags von arithmetischen Operationen gesetzt sind, ist ganz normal, denn dein Compiler generiert Code, der mathematische und logische Operationen enthält.
23
// Bit setzen weil Speicher frei: Bit = 1
// x |= FLAG
bitmap[array_index] |= bitnummer;

Damit setzt du nicht das Bit, sondern du verknüpfst die beiden Werte.

Hier ein Beispiel: http://ideone.com/viksw9 Beachte die Ausgabe.

Es muss also folgendes sein:
bitmap[array_index] |= 1 << bitnummer;

Bit löschen geht mit:
bitmap[array_index] &= ~(1 << bitnummer);

24
Offtopic / Re: Status-Update
« am: 25. November 2014, 23:13 »
Willkommen zurück. Ja, wir sind noch da, und uns geht es besser denn je   :lol:

Damals war ich auch noch recht unerfahren im IT-Sektor und meinte, ich könne innerhalb weniger Jahren ein OS entwickeln, welches funktioneller und sicherer ist als Windows (sollte Vivian heißen, wenn sich jemand erinnert  :wink: ). Damals bin ich aber, um ehrlich zu sein, nie weiter gekommen als ein Boot-Programm zu schreiben welches 3 unterschiedliche Funktionen anzeigt, welche per Enter-Taste ausgewählt werden konnten.
Also sicherer als Windows ist das doch zumindest. ;)

Und wäre Lowlevel-Coding auf Servern überhaupt empfehlenswert? (Lohnt sich die extra Geschwindigkeit, da Erlang bereits schnell ist? Wie hoch ist die Gefahr, den Server mit einer fehlerhaften Code zu zerstören usw. ?)
Also um einen Server zu zerstören, müsste man schon wirklich unglaublich viel Daten in ein Register packen, dass da der Druck über das Limit von Kupfer steigt (laut Wikipedia 200-250 N/mm^2 und damit deutlich mehr als andere Leiter wie Aluminium). Die Compilerentwickler haben da einige Techniken entwickelt, die sowas außerdem verhindern sollen: ftp://gcc.gnu.org/pub/gcc/summit/2004/Fighting%20Register%20Pressure.pdf Also ich seh da eigentlich kein Problem, wenn du entsprechende Vorsichtsmaßnahmen triffst  :mrgreen:
25
In solchen Fällen ist es sinnvoll zu schauen, was überhaupt noch funktioniert.
26
In EIP sollte ein Wert stehen, der auf deinen Code zeigt, in ESP sollte eine Adresse stehen, die auf einen der dir bekannten Stacks liegt. Du legst die ja mit pmm_alloc an, bzw. die sind direkt im Kernel. In den Segmentregistern sollten gültige Werte stehen.
27
Den könntest du erkennen, indem du schaust, ob die anderen Werte auf dem Stack plausibel sind.
28
Ich hätte noch zwei, drei Theorien einzuwerfen: Vielleicht schaust du gerade auf den falschen Wert (etwas das gar nicht der Error Code ist), oder deine Ausgabefunktion ist fehlerhaft. Und der Klassiker kaputter Stack ist auch immer dabei.
29
Bei den Fehlercodes ist die Betrachung in Hexadezimal am sinnvollsten. Der Wert ist also 0x102. Das setzt sich aus zwei Teilen zusammen: Die unteren 3 Bits geben an, wo der Fehler aufgetreten ist (IDT oder GDT), und die restlichen Bits geben den Eintrag an. (Siehe auch Kapitel 6.13 in Volume 3 der Manuals.) Die 2 heißt IDT und 0x100 ist die Adresse des 32. Eintrags (0x100 / 8 = 32), also des Timer IRQs. Das heißt deine IDT wird vermutlich überschrieben, unerreichbar gemacht (Paging) oder verschoben (LIDT), bevor der nächste Timerinterrupt auftritt. Außerdem ist das Aufrufen aus dem Userspace (int 0x20) nicht erlaubt. Glaube das gibt auch diesen Fault.
30
Zitat
Wie lautet der Fehlercode?
Der Fehlercode also die Nummer des Interrupts "cpu->intr" ist 13 was meiner Belegung nach einem General Protection Fault entspricht.
Der Fehlercode ist in cpu->error.

Zitat
Gerade weil es an so vielem liegen kann, ist der komplette Quelltext hilfreich. An dem geposteten Code kann ich nichts falsches entdecken.
dann werde ich mal schauen ob ich mein projekt irgendwie auf github bekomme...
sollte ja nicht so schwer sein... aber eigtl sollte ja nur der code den ich gepostet habe für mein problem releavant sein... oder? kann es daran liegen dass meine physische Speicherverwaltung nicht richtig funktioniert und die pmm_alloc() Funktion nicht funktioniert?
Das wäre eine Möglichkeit von mindestens 1596.
31
Also das mit dem Quellcode ist eher schwierig weils ziemlich viel ist an dem es liegen könnte, aber ich kann den relevanten Teil mal hier hochladen
Gerade weil es an so vielem liegen kann, ist der komplette Quelltext hilfreich. An dem geposteten Code kann ich nichts falsches entdecken.

die Logging Funktion meines Emulators kann ich leider nicht nutzen, weil ich einen echten PC als Emulator verwende und von einem USB-Stick boote (Die quemu installation ist desöfteren gescheitert und ein ordentliches Image hab ich dank fehlendem grub legacy auch nicht hingekriegt).
Das ist nicht gut. Gerade am Anfang ist ein Emulator sehr nützlich.

Aber ich habe es jetz hinreichend getestet, also wenn nur ein Task läuft ist alles in Ordnung, aber sobald ich mehrere tasks laufen habe, eigtl immer genau dann wenn der Taskswitch stattfindet, also beim Timerinterrupt, bekomme ich einen General Protection Fault, der von meinem Interrupt Handler bearbeitet wird und dann hält mein Kernel gewollt an.
Wie lautet der Fehlercode?
32
Also um dir zu helfen, brauchen wir mehr Informationen. Einmal ist der Quellcode interessant, falls du den irgendwo auf github oder einem anderen Repository hochladen könntest, wäre das am einfachsten für uns da reinzuschauen. Außerdem solltest du dich mit den Logging-Funktionen deines Emulators auseinandersetzen. Zum Beispiel hab ich das vor einiger Zeit mal hier an einem konkreten Problem erklärt: http://forum.lowlevel.eu/index.php?topic=3247.msg37696#msg37696
33
Ist das so wie du das gemeint hast?
Jep, genau sowas. Einen Bug sehe ich da allerdings noch. Der macht sich zwar nur in einem der Grenzfälle bemerkbar, aber ein Auge für sowas zu entwickeln, ist nie schlecht. Was passiert wenn, du
long[] testarr = {0,0,0,0,0,0,0,0,0}; /* die anzahl nullen ist egal */verwendest? Und wie korrigiert man das? Auf Grund der Uhrzeit1) entschließe ich mich mal, das als Rätsel zu formulieren. Falls du nicht auf die Lösung kommst, geht die Schnitzeljagd hier los: http://pastebin.com/JdPGFGn1 ;)

Die Entdeckung solcher Probleme meinte ich übrigens mit "gründlich Testen". Andere Testfälle, wären beispielsweise noch ein leeres Array, oder ein Array mit 0xfffffffff belegt. Einfach mal gucken, ob die Funktion, da dann auch das tut, was sie soll, auch wenn es ggf. nur eine Fehlermeldung (oder Rückgabewert -1) ist.


Bei dem 2. bin ich mir allerdings nicht sicher wie ich das hinkriege dass ich das niedrigste gesetzte Bit in einem Integer finde.

Das ist schwer zu erklären ohne gleich den Code zu servieren, deswegen hier mal eine einfache Implementierung:

    private static int bitscanforward(int x) {
int i;

for (i = 0; i < 32; i++) {
if ((x & (1 << i)) != 0)
return i;
}

/* ups gar kein bit war gesetzt */
return -1;
}

Ein (32-Bit-)Integer hat 32 Bits. Deswegen habe ich da eine Schleife, die von 0 bis 31 läuft. Der Wert von 1 << i ist mathematisch gesehen 2^i und ist in Binärdarstellung eine Zahl, die genau ein Bit auf 1 gesetzt hat (nämlich das i-te) und alle anderen sind 0. Das heißt wenn wir x & (1 << i) auswerten, hat dieses ein Ergebnis ungleich 0, wenn sowohl x als auch 1 << i an der selben Bitposition ungleich 0 sind. Also genau dann, wenn x an der i-ten Bitposition ungleich 0 ist. Weil wir die Schleife aufsteigend von 0 an durchlaufen, finden wir mit dieser Methode das niedrigste Bit ungleich 0. (Das ist etwas, das man sich im Zweifelsfall mal aufmalen sollte.)

Deine (hoffentlich korrigierte) Funktion und meine Funktion kannst du nun kombinieren, um deine pmm_alloc zu implementieren. Deine Funktion sollte einen Eintrag in der Bitmap ungleich 0 finden, und meine Funktion sollte darin den Index bestimmen. Der Algorithmus ist dann 2)

index = indexArrayValNotNull(bitmap);
bit = bitscanforward(bitmap[index]);
page_nummer = index * 32 + bit; // 32 pages pro eintrag in "bitmap"
adresse = page_nummer * 4096; // jede page ist 4096 bytes groß

Und zu der Frage, ob nun char* oder void* oder unsigned int: Eigentlich absolut nicht egal, aber solange mir keiner widerspricht: unsigned int.

Zur Fehlerbehandlung: Wenn deine Funktion (gerechtfertigt) -1 zurück gibt, dann ist der Speicher übrigens komplett belegt, und dein OS sollte anhalten. Meine Funktion sollte nie -1 zurückgeben, wenn du sie mit Bitmap-Einträgen fütterst, die ungleich 0 sind.

1) :mrgreen:
2) Individualisierung angebracht und erwünscht
34
OS-Design / Re: YourOS
« am: 16. November 2014, 04:02 »
Und wieviel RAM hast du der virtuellen Maschine zugewiesen?

Keine Ahnung, den Standardwert. Vermutlich 128 MB.
35
OS-Design / Re: YourOS
« am: 16. November 2014, 03:29 »
Also bei mir steht nach dem Booten CR0=80000013. Also sind bei mir die Bits für Cache disable und No Write-Through gelöscht.
Das heisst bei mir wird der Cache aktiviert.
Mit dem BTC als Instruktion? Dann wäre das sehr seltsam, weil das ja hieße, dass vorher der Cache tatsächlich deaktiviert war. <rhetorisch>Warum sollte das jemand tun?</rhetorisch>

Wieso muss ich den Cache flushen, wenn die Instruktionen sowieso erst später ausgeführt werden (also nachdem ich den Cache deaktiviert habe)?
Ich muss zugeben, dass ich das auch erst gelesen habe, als ich mich über die Funktionsweise von CD informiert habe. Ich vermute, dass durch das setzen von CD die CPU angewiesen wird, nichts mehr in den Cache zu laden. Aber der restliche Mechanismus, der den Cache nutzt bleibt aktiv. Das heißt, die CPU versucht weiterhin den Cache zu benutzen, und wenn sie etwas drin findet, dann nutzt sie es auch. Also würden Daten, die früher einmal in den Cache geladen wurden, auch nach dem deaktivieren weiterhin darin benutzt werden.

Eine Theorie, die ich (ohne entsprechende Belege) hätte, ist, dass dieses Flag eher dafür gedacht ist, bei Multiprozessorsystemen das Verhalten der CPUs untereinander zu steuern, und nicht wirklich für den Ein-Prozessor-System-Fall gedacht ist. Das Flushen hätte dann den Sinn, dass alle Prozessoren nach dem Deaktivieren des Caches dieselbe Sicht hätten (nämlich eine, die nicht durch die eigenen Caches beeinflusst wird).

Danke fürs Ausprobieren :wink:. Gab es irgendwelche Fehler?
Mit welchen Spezifikationen hast du mein OS getestet? Danke auch für deinen "Fehlerreport" (das mit dem btc).
Ich hab da nicht viel getestet. Das war ein Qemu 1.1.2 unter Debian, dem ich einfach deine ISO mitgegeben habe.
36
OS-Design / Re: YourOS
« am: 15. November 2014, 15:54 »
Meinst du mit "Cache aktivieren" diesen Abschnitt? https://github.com/Gurgel100/Kernel/blob/develop/cpu.c#L202

Was du da tust ist den Cache Deaktivieren. Ich habe, während ich deine ISO gebootet habe, einfach mal im Bootmenü die Register im QEMU Monitor anzeigen lassen, und er sagt mir CR0=00000011. Sobald dein OS geladen ist, ist CR0=e0000013. Also sind nun die Bits für Cache Disable und No Write-Through gesetzt.

Das Manual sagt in Volume 3, Abschnitt 11.5.1: "For highest processor performance, both the CD and the NW flags in control register CR0 should be cleared." Außerdem siehst du vermutlich keine positive oder negative Geschwindigkeitsänderung, weil du den Cache nicht geflusht hast. Auch mit dem deaktivierten Cache werden existierende Einträge weiterhin genutzt. (In Tabelle 11-5, in der Zeile für CD=1, NW=1: "Read hits access the cache; read misses do not cause replacement.")

Außerdem finde ich die Verwendung der BTC-Instruktion etwas seltsam. Das kehrt ja nur das Bit um. Ein Bit setzen kannst du damit nicht, wenn es vorher schon gesetzt war.
37
Das ist perfekt. Für diese Zwecke ist sie C ähnlich genug.
38
Mal eine Gegenfrage: Mit welcher Programmiersprache bist du denn sonst so unterwegs? Könntest du darin eine Funktion schreiben, die in einem Array bestimmter Größe den Index eines Eintrags zurückliefert, der ungleich Null ist? Und könntest du eine weitere Funktion schreiben, die in einem Integer den Index des niedrigsten gesetzten Bits findet? (Darfst sogar annehmen, dass dieser Integer ungleich 0 ist. Kann man ja später mit der ersten Funktion kombinieren.)

Mein Vorschlag wäre, erstmal diese beiden Funktionen (am besten in der dir vertrauten Sprache) zu schreiben und - ganz wichtig - gründlich zu testen. (Randbedingungen/Grenzfälle überlegen!) Es muss (sollte am besten sogar) nicht in deinem OS sein, sondern einfach in einem ganz normalen kleinen Testprogramm unter Linux/Windows/etc. Dann findest du sicherlich selbst viele Probleme, die in dem geposteten Codeschnipsel bestehen. Das ist zumindest meine Hoffnung.
39
Also beispielsweise ein Array für die Umwandlung Scancode -> Keycode und für jedes Tastaturlayout jeweils ein Array für die Umwandlung von Keycode -> Zeichen.

Oder direkt jeweils ein Array Scancode -> Zeichen für jedes Tastaturlayout.

Was bei dem Artikel KBC zu beachten ist, ist dass das letzte kprintf("%c", keycode); fälschlicherweise suggeriert, dass der Keycode tatsächlich schon das Zeichen ist. In týndur, wo der Code herkommt, ist das nur eine abstrakte Zahl, die anschließend erst noch in ein dem Tastaturlayout entsprechendes Zeichen gewandelt werden muss. Ein "%c" zur Ausgabe von keycode würde also nur Murks ausgeben.
40
Hi und willkommen an Board!

Und mir ist nicht ganz klar wie ich diese umsetzen soll... also IRQ_BASE is ein int und wahrscheinlich 32 wenn ich das richtig interpretiere.
ab 32 fangen die Hardware Interupts an und IRQ_BASE + 1 sollte der von der Tastatur sein also 33. Soweit richtig oder ?
Dann die Referenz auf irq_handler ist ja einfach die Funktion die unten drunter erklärt ist.
Kann ich alles bestätigen.

Was macht jetzt aber register_intr_handler ?
Also soweit ich das verstehe müsste die Funktion ja den intr_stub 33 mit der Funktion irq_handler verknüpfen oder ?
Also muss sozusagen in dem Handler der in Tutorial 5 erstellt wurde für 0x21 die Funktion irq handler gesetzt werden oder sehe ich das falsch?
So ist es. register_intr_handler kann beispielsweise den übergebenen Zeiger irq_handler in ein Array1) an Index 0x21 eintragen. Der Interrupt-Handler (handle_interrupt) könnte dann bei einem Interrupt in dieses Array schauen (an Index cpu->intr), und wenn dort etwas eingetragen ist, diesen Zeiger aufrufen. Die Syntax für sowas ist nicht ganz einfach, aber wenn du nach "array of function pointers" oder so googelst, solltest du da etwas bekommen. Ansonsten einfach hier nachfragen.

Die Signatur von register_intr_handler sollte sowas wie void register_intr_handler(int int_no, void (*handler)(uint8_t)) sein.

1)Das Array müsste dann theoretisch 256 Elemente groß sein, weil es 256 Interrupts gibt, aber du kannst dir ja auch mal überlegen, welche Interrupts überhaupt alles registeriert werden müssen, und ob es nicht auch mit weniger geht. register_intr_handler und der Interrupt-Handler müssten dann entsprechend cleverer sein.
Seiten: 1 [2] 3 4 ... 81

Einloggen