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 - Korona

Seiten: [1] 2 3 ... 5
1
Offtopic / Re: Disassembler
« am: 06. June 2009, 14:22 »
Das is Sections schreiben ist kein Problem,  beim Disassemblieren kann es allerdings sein dass vor einem "Label" (also vor einer Stelle an die gesprungen wird, Labels gibt es ja in der Binärdatei nicht) noch einige Padding-Bytes kommen. Unter Umständen kann das dazu führen dass die Instructions nicht richtig interpretiert werden, weil der Disassembler den Anfang der Instruktion nicht richtig erkennt. NDISASM scannt dazu iirc alle jump Instructions und disassembliert dann von den Zieladressen an.
2
Offtopic / Re: Disassembler
« am: 05. June 2009, 22:01 »
Naja, einen Assembler zu schreiben ist nicht gerade schwer, ein Disassembler ist eventuell etwas schwerer, da du ja nicht einfach an irgendeiner Adresse drauf los disassemblieren kannst, sondern beachten musst was Code, was Daten und was Padding ist, aber ansonsten sehe ich ja kein Problem.
3
Lowlevel-Coding / Re: IDT und PIC
« am: 02. August 2008, 23:38 »
Der Descriptor ist so wie du ihn da stehen hast nicht korrekt: Das Offset steht in den ersten zwei Bytes (dort stehen die niedrigeren  16 Bits des Offsets) sowie in den letzten zwei Bytes (dort stehen die höheren 16 Bits des Offsets). Dein Code trägt nur die unteren 16 Bits ein. Da NASM und andere Assembler keine Bitwise-Operationen auf Labels zulassen kannst du das korrekte Offset nicht einfach so eintragen:

dw IRQ_00 & 0xFFFF
dw 08h
db 0
db 10001110b
dw IRQ_00 >> 16

Die einfachste Lösung dafür ist, die beiden Offsetfelder zunächst freizulassen und vor dem Laden der IDT auszufüllen, etwa so:
; aufruf mit eax = interrupt nummer und edx = handleraddresse
setzeIdtHandler:
   mov [idt + eax * 8], dx
   shr edx, 16
   mov [idt + eax * 8 + 6], dx
   ret
4
Lowlevel-Coding / Re: IDT und PIC
« am: 02. August 2008, 19:01 »
Von Intel reserviert heißt bei den ISRs lediglich,  dass dieser ISR von späteren Prozessorgenerationen als Exception benutzt werden könnte und er daher nicht für deine Softwareinterrupts benutzt werden sollte.

Zum Generieren der IDT kannst du dir einfach das NASM Manual ansehen, besonders diese Abschnitte:
http://alien.dowling.edu/~rohit/nasmdoc4.html#section-4.5
bzw.
http://alien.dowling.edu/~rohit/nasmdoc4.html#section-4.3
5
Lowlevel-Coding / Re: IDT und PIC
« am: 02. August 2008, 17:35 »
dw IRQ_00
                dw 08h
                db 0
                db 10001110b
                dw 0
Ich nehme an, das du in diesen Eintrag zu Laufzeit die richtige Offsetaddresse einfügst? So wie er in diesem Codeabschnitt definiert ist, ist der Eintrag noch nicht korrekt.

Zitat
Muss ich, damit ich die ersten Software-Interrupts habe 36 dieser Einträge erstellen?
Diese Frage verstehe ich nicht ganz, wenn dein Interrupt per "int 0" aufgerufen wird funktioniert der Handler doch schon. Du brauchst nur so viele IDT Einträge, wie du Interrupts hast, es ist aber sinnvoll zumindest die ersten 32 Einträge zu füllen, dort befinden sich Exceptionhandler. Meistens erstellt man einfach eine IDT mit allen 256 Einträgen - so kann man sie später einfach erweitern bzw. auf einen Default-Handler verweisen lassen und die paar Bytes die verschwendet werden sind auf heutigen PCs wohl vollkommen egal.

Eine Liste der Exceptions findest du in den Intelmanuals. Falls eine Exception auftritt empfiehlt es sich normalerweise das laufende Programm zu beenden, falls die Exception nicht behoben werden kann. Manche Exceptions lassen sich beheben, es ist zum Beispiel möglich (wenn man Paging implementiert hat) Pages aus dem RAM auf die Festplatte zu schreiben (um physischen Speicher zu sparen). Die jeweilige Page markiert man dann als nicht-present. So wird beim Zugriff auf die Page eine Exception (Pagefault) ausgelöst und der Kernel kann die Page zurück in den RAM laden und das Programm einfach weiter laufen lassen. Zunächst kannst du bei Exceptions einfach eine Fehlermeldung anzeigen und abbrechen. Solange du kein Multitasking hast kannst du mit ihnen nicht sehr viel Sinnvolles anfangen. Einige Exceptions schreiben außerdem einen Fehlercode auf den Stack, der nährere Informationen zu der Exception gibt.

Für die übrigen Interrupts gibt es keinen Standard, du kannst sie für beliebige Funktionen verwenden. Unter Linux laufen z.B. alle Kernelaufrufe über den Interrupt 0x81. Die anderen Interrupts werden von Linux nicht benutzt. (Evt. gibt es Treiber die auch andere nutzen, alle normalen Anwendungen nutzen nur 0x81)
6
OS-Design / Re: Mein Os: managarm
« am: 02. August 2008, 11:52 »
Falls zu wenig Speicher vorhanden ist wird einfach eine Meldung auf die serielle Schittstelle ausgegeben. Das sollte ich auf jeden Fall noch ändern und eine Meldung auf den Bildschirm ausgeben.

An der Geschwindigkeit gibt es natürlich allgemein noch einiges zu tun. Nachdem ich eine vernünftige Speicherverwaltung implementiert habe werde ich da mal einige Optimierungen vornehmen.

Ansonsten vielen Dank fürs Testen. :) Welchen Emulator oder welche Hardware hast du eigentlich dazu benutzt?
7
OS-Design / Mein Os: managarm
« am: 01. August 2008, 19:24 »
Hi,
nach vielen Monaten Entwicklungsarbeit befinden sich der Kernel und einige grundlegende Bestandteile meines Betriebssystems jetzt endlich auf einem halbwegs benutzbarem Niveu. Ich poste diesen Thread in der Kategorie "OS Design" da mein OS ein relativ exotisches Design besitzt, das ich hier vorstellen möchte.

Mein OS baut nämlich auf einer virtuellen Maschine auf; alle Anwendungen und Treiber sind in einer Programmiersprache geschrieben, die zu Bytecode kompiliert wird. Der Bytecode wird dann von der virtuellen Maschine just-in-time (unmittelbar vor dem Ausführen) zu nativem x86 Code kompiliert. Das hat den Vorteil, das Speicherheitslücken wie z.B. Buffer Overflows auf dem OS nicht auftreten können: Die virtuelle Maschine verhindert, dass auf nicht vorhandene Arrayelemente zugegriffen werden kann. Der "unsichere" Code der auf dem Computer läufen muss ist also viel kleiner als bei einem monolithischen Kernel, nur die virtuelle Maschine und der Kernel können potentiell Fehler und Kernelpanics auslösen. Anders als bei monolithischen Kernels können die Treiber keine Panics auslösen. Anders als bei einem Microkernel können sie trotzdem in Ring 0 laufen - ihre Sicherheit ist ja bereits durch die VM garantiert. Im Idealfall ist das Betriebsystem also so schnell wie ein monolithischer Kernel (oder sogar noch schneller, da Anwendungen auch in Ring 0 laufen) und hat die Sicherheit eines Microkernels.

Als Sprache verwende ich dabei nicht eine der herkömmlichen Sprachen Java oder C# bzw. Microsoft's .NET sondern eine für diesen Zweck entwickelte Sprache (namens Korona). Java kann mit einigen wichtigen und nützlichen Sachen nicht umgehen, die für Treiber benötigt werden (etwa vorzeichenlose Datentypen), .NET ist recht kompliziert und intern sehr unschön.

Ein Diskettenimage zum Testen sowie den Sourcecode gibts auf: http://code.google.com/p/managarm/

EDIT: Als Programme sind im Moment nur cat, echo und ls vorhanden. (und natürlich cd)
EDIT: Es wird im Moment nur das QWERTY Tastaturlayout unterstützt. Wer damit nicht vertraut ist:
y = z
z = y
ö = ;
ö + shift = :
ä + shift = "
- = /
? = -


Das OS hat allerdings noch einige Grenzen:
- Es benötigt über 128 MB Speicher, im schlimmsten Fall etwa 150 MB. Das liegt weniger am Design als an der Implementierung: Der Memory Manager gibt im Moment überhaupt keinen Speicher frei (ich hatte zwischenzeitlich einen Slaballocator eingebaut, der wurde aber irgentwann wieder entfernt). Garbage Collection ist zwar implementiert aber deaktiviert. In den nächsten zwei Wochen werde ich daher einen vernünftigen Speichermanager schreiben.
- Auf Bochs und VirtualBox (auf einer CPU ohne VM Extensions; falls jemand eine mit VM Extensions hat wäre es sehr nett wenn er das testen würde =)) ist das OS recht langsam. Auf QEmu ist die Geschwindigkeit akzeptabel, auf VMWare ist sie am besten.
EDIT: Auf QEmu kann es schon bis zu einer Minute dauern, bis die Shell startet und man etwas auf dem Bildschirm sieht.

Mittlerweile ist das Projekt sehr groß geworden und die Todo-List wird eher größer als kleiner. Als eine einzige Person kann ich es kaum schaffen alle meine Vorstellungen (TCP/IP Stack, ATAPI, verschiedene Dateisysteme, einen Usermanager, SMP, VESA und einen Windowmanager, einen Packetmanager, Java Support, .NET Support und vieles mehr) zu verwirklichen. Falls also jemand Interesse an dem Projekt hat und schon etwas Erfahrung mit der OS Entwicklung hat würde ich mich freuen, wenn er sich bei mir melden würde. =)
8
Offtopic / Re: Betriebssystem für FileServer
« am: 30. July 2008, 12:32 »
Dazu gibt es sicher viele Tutorials im Web, google einfach mal nach "Setting up sshd" (sshd ist der ssh Daemon/Server).
9
Lowlevel-Coding / Re: IDT laden
« am: 24. July 2008, 16:54 »
/* Defines a IDT pointer */
struct idt_ptr
{
unsigned int base;
unsigned short size;
} __attribute__((packed));
ist falsch. Die Größe steht in den ersten zwei Bytes, nicht in den letzten.
10
Lowlevel-Coding / Re: StupidOS in C
« am: 24. July 2008, 16:47 »
Es ist sehr viel angenehmer GRUB zu benutzen und direkt im Protected Mode anzufangen als einen Realmode Bootloader zu schreiben.
GRUB erspart dir viele lästige Dinge wie das Einschalten des A20 Gates, das Abfragen der Memory Map etc.
Wenn du deinen eignen Bootloader schreibst musst du dich entweder mit Dateisystemen herumschlagen oder spezielle Sektoren auf der Diskette / CD / Festplatte für deinen Kernel reservieren. Die erste Lösung ist umständlich, die zweite ist IMHO ein Hack. :P
11
Zitat
Zitat
Als erstes holen wir uns die Bootmsg aus dieser Variable.
Ich würde sagen die Adresse der Bootmsg, nicht die Bootmsg selber.
naja, ohne die adresse auch keine nachricht, oder...? aber, gut zu wissen :)
Zwischen deiner Hausnummer und deinem Haus ist m.E. schon nochmal ein großer Unterschied. Zumindest macht es einen Unterschied ob ich deine Hausnummer oder dein Haus besitze. :wink:  :-P
das stimmt. hier aber brauchen wir die adresse, um uns die nachricht holen zu können... oder, denke ich da jetzt gerade in die falsche richtung...
Ja, aber wir "holen" uns die Nachricht mit der Anweisung überhaupt nicht. In das Register wird nunmal die Addresse der Nachricht geschrieben. Auf die Nachricht selber wird hier garnicht zugegriffen, das macht erst der BIOS-Interrupt.
12
Ja, das ist ein Problem, wenn du zulässt dass eine PID nach dem Beenden des Prozesses nochmal vergeben wird.
Eine Lösung wäre PIDs nicht mehrmals zu vergeben. (dazu wäre es vorteilhaft mindestens 64 Bit oder gar 128 Bit lange PIDs verwenden; ich nutze dieses Modell)
Eine andere Möglichkeit ist, nur die Hälfte der Bits aus denen die PID besteht zur Bestimmung des Prozesses zu verwenden und die andere Hälfte als eindeutigen Schlüssel für den Prozess zu verwenden. Bei einem Systemcall kann der Kernel dann den Schlüssel den er aus der PID entnimmt mit dem Schlüssel der in der Taskstuktur gespeichert ist vergleichen. Stimmen sie überein so ist die PID gültig, andernfalls bricht der Kernel mit einem Fehler ab. Windows verwendet AFAIK dieses Modell.
13
OS-Design / Re: Speicherverwaltung
« am: 27. June 2008, 22:37 »
Um einen freien Speicherbereich beliebiger Größe zu finden kannst du ja einen B-Tree mit Knotengröße = Pagesize implementieren, wobei du für jedes Element jeweils die Größe des Blocks (als Schlüssel) und die Addresse speicherst. Damit hast du O(log n) statt O(n) Laufzeit. Falls man zu jedem Knoten noch die Addresse des nächsten Blocks und des vorherigen Blocks speichert + ein Flag das anzeigt ob diese frei oder belegt sind, kann man Speicherblöcke auch in O(1) spalten (oder in O(log n), wenn man den abgespaltenen Speicherblock wieder in den Tree einfügt) oder wieder zusammenführen. So werde ich warscheinlich meinen virtuellen Speichermanager implementieren, wenn ich irgentwann mal Zeit habe den zu überarbeiten (im Moment ist mir das noch zuviel Overkill und mir sind andere Features wichtiger :D). Bis jetzt habe ich ihn nur als binären Suchbaum implementiert, was eine worst-cast Laufzeit von O(n) hat.
14
Lowlevel-Coding / Re: Paging Fehler: Bit 31 in cr0
« am: 23. June 2008, 19:20 »
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.
15
Lowlevel-Coding / Re: Kernel stürzt ab
« am: 19. June 2008, 11:38 »
nasm -f elf ...
Siehe auch das NASM Manual.
16
Lowlevel-Coding / Re: Multitasking
« am: 09. June 2008, 13:40 »
Mit dem Stack der bei einem Interrupt benutzt werden soll (= dem Kernel Stack des jeweiligen Threads).
Für jeden Thread erstellst du einen Kernelthread und setzt vor jedem Taskwechsel den ESP Wert des TSS auf den Anfang des Kernelstacks des Threads der als nächstes laufen soll.
17
Lowlevel-Coding / Re: Multitasking
« am: 08. June 2008, 21:12 »
Des Weiteren brauche ich auch eine TSS für die VM8086 Tasks. Für diese hatte ich mir dass dann so geplant, dass ich einen Deskriptor in der GDT habe, den ich jedes mal nach belieben umbiegen, sollte der aktuelle Task ein Virtueller sein.
Ja, ein TSS reicht, du änderst dann einfach bei jedem Threadwechsel die ESP und SS Addressen.

Zitat
  • Taskwechsel beginnt
  • Kernel Page Directory laden
  • Neuen Task "suchen"
  • Page Directory des Tasks laden
  • Task starten
Wenn der Kernel in alle Prozesse gemappt ist entfällt der zweite Schritt. Cr3 Wechsel sind sehr teuer also solltest du den Kernel in alle Prozesse mappen.

Zitat
Da habe ich jetzt noch eine Frage:
Wie sieht dass dan im speziellen aus, wenn ich ein Programm starte, z.B. einen editor?
  • Task wird erstellt
  • Programm wird in eine freie Speicherstelle geladen
  • (und nun ?)
-> Virtuellen Adressraum erstellen
-> Auf der Programmdatei auslesen welche Speicherprogramme das Programm benutzt
-> Diese Speicherbereiche in den neuen Adressraum mappen und das Programm entsprechent dorthin laden
-> Einstiegspunkt aus der Datei lesen und neuen Thread erstellen mit diesem Einstiegspunkt als Startadresse
18
Lowlevel-Coding / Re: Paging
« am: 08. June 2008, 00:03 »
Hast du einen vernünftigen Stack? Eine GPF kann nur auftreten wenn dein Stacksegment oder der IDT Eintrag nicht present sind.
Poste mal deinen ISR Code, am Paging Code kann man nicht sehen, warum die GPF auftritt.
19
Lowlevel-Coding / Re: Multitasking
« am: 06. June 2008, 16:22 »
Aufs TSS kannst du nicht verzichten, beim Wechsel Ring3 -> Ring0 wird SS und ESP aus dem TSS gelesen. Ohne TSS kriegst du da eine GPF.
Du brauchst für jeden Thread einen Usermode und einen Kernelstack. Sonst könnte es passieren dass beim Aufruf von Interrupts der Stack überläuft. Da wie gesagt beim Ringwechsel SS und ESP neu geladen werden ist es auch garnicht möglich nur einen Stack zu verwenden.

Ich würde mir aber nochmal überlegen, ob du deiner Prozessstruktur Felder für Stacks gibst. Ich würde eher Threads als "Tasks" (auch kein klar definierter Ausdruck aber mir fält kein besserer ein) betrachten und Prozesse als die Umgebung in der Threads laufen. Sprich: Nicht Prozesse werden gescheduled, sondern Threads und Prozesse fassen lediglich alle Threads eines Address-Spaces zusammen.
20
OS-Design / Re: HAL
« am: 05. June 2008, 14:38 »
Das lässt sich nicht allgemeingültig sagen, das kommt stark auf deinen Kernel an. Ich habe einen Microkernel also lagere ich den PCI Treiber aus. Monolithische Kernel möchten den PCI Bus vielleicht innerhalb des Kernels verwalten.
Seiten: [1] 2 3 ... 5

Einloggen