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

Seiten: [1]
1
OS-Design / Re: Anfängerfragen zu Paging
« am: 07. August 2013, 20:12 »
Wenn du nun 1048576 Blöcke hast, aber dein System nur 256MB Speicher, dann liegt eine ganze Menge deiner Blöcke brach.
Das ist wohl wahr  :-(

blöd ist es nur wenn du zu wenig Blöcke hast. Dann kannst du nicht den ganzen Speicher verwenden, außer du "bastelst" was hinten dran (und sowas wird [zumindest bei mir immer] echt unschön).
In einem 32 bit System kann ich ja eh nur maximal 4GB adressieren und mit 1048576 Blöcken decke ich diese Größe ja ab.
2
OS-Design / Re: Anfängerfragen zu Paging
« am: 07. August 2013, 19:29 »
Leider ist sie mit "statisch" auch wirklich statisch :-(, was bedeutet das sie entweder zu groß oder zu klein dimensioniert ist, aber wohl in den wenigsten Fällen genau die passende Größe hat.
Wieso, im Datensegment wird doch genau so viel Speicher für die Bitmap reserviert, wie ich angegeben habe. Das heißt sie wird genau die Größe haben, um 1048576 Blöcke à 4kb darzustellen.
3
OS-Design / Re: Anfängerfragen zu Paging
« am: 07. August 2013, 18:57 »
Zunächst danke für deine Antwort :-).

Bis zum Pentium war das auch so. 4 KB Pages sind nur dann etwas unschön, wenn du 4 MB physischen Speicher am Stück hast und den komplett in den virtuellen Adressraum mappen willst. Dann musst du dafür extra eine Page Table anlegen, die 1024 Einträge hat, die aufsteigende Einträge X, X+4096, X+8192, usw... enthält, um jede der Pages einzeln zu mappen. Weil die Intel-Ingenieure dachten, dass man sich für diesen Fall die Page Table sparen könnte, haben die das Flag eingefügt, sodass schon der Eintrag im Page Directory den virtuellen Speicherbereich mappt.
Ok, das gibt Sinn :-D.

Man kann auch sagen, dass die Bits jeweils mit einer AND-Operation verknüpft werden.
Ah ok. Ich verstehe..

Es muss übrigens nicht zwingend der erste Eintrag sein, sondern jeder Eintrag kann dafür genutzt werden.
Wenn ich nicht den ersten Eintrag nehme, dann muss der Eintrag, den ich nehme, aber auf den ersten Eintrag zeigen und nicht auf sich selbst oder? Sonst würden die vorherigen Einträge doch verloren gehen, oder habe ich einen Denkfehler?

Zitat von: Jidder link=topic=3269.msg37950#msg37950 date=1375893270
Du kannst im Linkerskript sogar genaue Labels definieren, die dir sagen, wo der Kernel anfängt und aufhört
Oh das wusste ich nicht. Kennt jemand einen anschaulischen Artikel zu Linkskripts auf lowlevel.eu (oder sonst wo)? weil ich glaube da habe ich noch etwas Nachholbedarf.

Zitat von: Jidder link=topic=3269.msg37950#msg37950 date=1375893270
Die Bitmap ist zwar in der .data-Sektion und nicht auf dem Stack, aber es ist korrekt, dass die zusammen mit dem Kernel gemappt wird.
Achso, weil das eine globale/statische Variable ist, oder wieso? Weil ich glaube, dass Variablen, deren Gültigkeit z.B. nur in einer Funktionen besteht, auf dem Stack erstellt werden.
4
OS-Design / Anfängerfragen zu Paging
« am: 07. August 2013, 17:27 »
Hallo :-)
Ich möchte Paging in meinem Kernel implementieren. Die Grundidee hinter dem virtuellen Adressraum habe ich verstanden, allerdings ergeben sich trotzdem ein paar Fragen.
Auf der Wikiseite zu Paging heißt es bei der Page-Directory Tabelle:

Zitat von: Bit 7 des Page Directory Eintrags
Gibt die Größe der Page an. 0 steht für 4 kB, 1 für 4 MB (oder 2 MB bei Verwendung von PAE). Das S-Bit ist wirkungslos, wenn nicht im Steuerregister CR4 das PSE-Bit (4-MB-Pages) oder PAE-Bit (2-MB-Pages) gesetzt ist.
Ich dachte bisher, dass Pages immer 4kb seien, daher verstehe ich nicht, warum es hier eine Fallunterscheidung gibt :?

Außerdem frage ich mich, ob sich Bit 1 und Bit 2 nur auf den Page Directory Eintrag selbst beziehen oder auch auf die untergeordnete Pagetable. Wenn z.b. Bit 2 nicht gesetzt ist, können Ring 3 Tasks dann trotzdem auf untergeordnete Pagetable Einträge zugreifen, wenn bei diesen dann das 2. Bit gesetzt ist, oder "vererbt" sich das quasi von dem Page Directory auf die untergeordnete Page Table?

Im Tutorial zu Paging steht unter Dynamisches Mapping, dass es einen Trick gäbe, um die Paging-Strukturen zu mappen:
Zitat von: Paging Tutorial - Dynamisches Mapping
Für das Mappen eines Page Directory und allen zugehörigen Page Tables gibt es einen Trick: Wenn ein Eintrag eines Page Directory wieder auf ein Page Directory (z.B. sich selbst) zeigt, dann wird dieses Page Directory an dieser Stelle als Page Table verwendet. Dadurch werden alle enthaltenen Page Tables hintereinander in den virtuellen Speicher gemappt. Dieser Trick wird oft für das aktuelle Page Directory benutzt, d.h. ein bestimmter Eintrag in jedem PD zeigt wieder auf das PD selbst.
Das heißt, wenn ein Page Directory Eintrag auf sich selbst zeigt, dann wird es selbst zum ersten Page Table Eintrag und alle anderen Page Directory Einträge müssten dann ja zu weiteren Page Table Einträge werden, wodurch dann die gesamte Page Directory Tabelle gemappt wird, oder wie? Das heißt, es gäbe Sinn, den ersten Page Directory Eintrag immer auf sich selbst zeigen zu lassen - habe ich das richtig verstanden?

Zitat von: Paging Tutorial - Dynamisches Mapping
Beim Kernelstart müssen einige Bereiche gemappt werden:
  • Der Kernelcode selbst
  • Der Videospeicher von B8000 bis BFFFF
  • Evtl. Multiboot-Strukturen, die noch verwendet werden sollen
  • Zum Zeitpunkt der Paging-Initialisierung schon dynamisch angelegte Kerneldaten, z.B. die Bitmap der physischen Speicherverwaltung
Dass die ganzen Bereiche, die vor der Paging Initialisierung erstellt wurden, gemappt werden müssen erscheint mir ja logisch. Nur bin ich mir nicht sicher, woher ich denn weiß, wo der Kernelcode selbst im Speicher zu finden ist. Also dem Linkscript kann ich entnehmen, dass mein Kernel bei 0x100000 beginnt und der Stack ist zu Beginn an der 2MB Grenze gesetzt. Heißt das denn auch, dass mein Kernelcode also vollständig zwischen 0x100000 und 0x200000 liegt und mit einer Größe von 1MB also 256 Pages beansprucht? (Ich vermute mal: nein :()
Zudem heißt es, dass z.b. Daten, wie die Bitmap der physischen Speicherverwaltung als dynamisch angelegte Kerneldaten gemappt werden müssten. Die Bitmap selbst habe ich aber garnicht dynamisch angelegt und das Tutorial zur physischen Speicherverwaltung legt sie ebenso statisch auf dem Stack an wie ich, was bedeutet, dass sie doch mit dem Kernelcode automatisch mitgemappt werden müsste - korrekt?

Ich hoffe ich habe nicht allzu wenig verstanden :|,

lg
Developer30
5
Lowlevel-Coding / Re: Verständnisproblem zu TSS
« am: 05. August 2013, 18:30 »
Danke für deine Antwort  :-)
Das hat mir sehr weitergeholfen die Aufgabe des TSS zu verstehen und mir den Ablauf nochmal im Kopf zu verdeutlichen. Dadurch hab ich es jetzt auch hinbekommen, meinen Scheduler für Ring 3 zu erweitern.
Verständnisproblem gelöst!  8-)
6
Lowlevel-Coding / Verständnisproblem zu TSS
« am: 05. August 2013, 16:15 »
Hallo, ich bins mal wieder  :-D

Ich versuche Software-Multitasking zu implementieren. Auf Ring 0 klappt das auch schon super. Jetzt möchte ich das ganze noch zusätzlich für Ring 3 auf die Beine stellen. Ich orientiere mich dabei an diesem Tutorial.

Zitat von: Tutorial
Was ändert sich für uns mit Ring-3-Tasks? An sich ist es nicht viel. Wie oben schon angemerkt, kommt zum bereits Bekannten nur noch ein Stackwechsel dazu.
Das heißt, es gibt jetzt 2 Stacks pro Task, User- und Kernelstack. Soweit, so gut.

Zitat von: Tutorial
Wenn der Prozessor bei einem Interrupt in Ring 3 ist, also einen Ringwechsel durchführen muss, sichert er esp und ss auf den Stack (wie es in struct cpu_state schon vorgesehen ist). Beim Zurückspringen aus dem Interrupt mittels iret stellt er diese Register auch wieder her.
Auf welchen Stack sichert er esp und ss? Wahrscheinlich ja auf den Kernelstack des alten Tasks.

Zitat von: Tutorial
Nachdem er die Register gesichert hat, lädt der Prozessor den Kernel-Stack (bestehend aus ss und esp). Diese beiden Werte kommen aus dem aktiven Task State Segment (TSS).
Jetzt lädt er also den Kernel Stack des nächsten Tasks aus der TSS. An dieser Stelle frage ich mich, wann tut er das? Beim Betreten oder beim Verlassen der ISR? Oder macht er das garnicht automatisch und ich muss das irgendwo tun?

Bei der Implementierung der TSS steht im Tutorial außerdem folgende Codezeile:
Zitat von: Tutorial
tss[1] = (uint32_t) (new_cpu + 1);
Dazu frage ich mich: Wieso wird der Zeiger um 1 erhöht?

Ich hoffe meine Fragen sind (irgendwo) nachvollziehbar.

lg
Developer30
7
Lowlevel-Coding / Re: IRQ1 / Tastatur funktioniert nicht?
« am: 04. August 2013, 18:25 »
Ok, ich habe das mal so umgesetzt. Es funktioniert, wie zu erwarten war  :-)
Danke :wink:
8
Lowlevel-Coding / Re: IRQ1 / Tastatur funktioniert nicht?
« am: 04. August 2013, 17:08 »
d.h. ich definiere in Assembler Labels, die ich dann über extern in C/C++ eintragen kann und rufe meine eigentliche C/C++ Funktion dann mit call auf? Habe ich das richtig verstanden?
9
Lowlevel-Coding / Re: IRQ1 / Tastatur funktioniert nicht?
« am: 04. August 2013, 16:50 »
Ja, ich sende ein EOI.

Ich habe mein kleines Projekt mal hochgeladen. Ich wäre sehr dankbar, wenn ihr eventuell selbst mal einen Blick in mein Code werfen könntet. Ich bin für (sonstige, stilistsiche) Verbesserungsvorschläge gerne offen und hoffe, dass der Fehler so besser gefunden werden kann.

Hier der Downloadlink: http://www.file-upload.net/download-7922666/os.tar.gz.html

lg
Developer30
10
Lowlevel-Coding / Re: IRQ1 / Tastatur funktioniert nicht?
« am: 04. August 2013, 14:27 »
Lies den Scancode in der ISR von der Tastatur, dann kommen auch wieder IRQs.

Bezwecke ich das nicht mit inb(0x60)?

In meiner _irq1 Prozedur erzeuge ich eine Bildschirmausgabe, sodass ich ja sehen sollte, wenn eine Taste gedrückt wird. Außerdem lade ich mit inb(0x60) den Scancode und setze danach EOI für den IRQ1.
11
Lowlevel-Coding / IRQ1 / Tastatur funktioniert nicht?
« am: 04. August 2013, 12:57 »
Hallo  :-)

Ich möchte gerne Tastatureingaben mit dem IRQ1 abfangen. Dazu habe ich die PICs initialisiert und für jeden IRQ eine Funktion in der IDT eingetragen. Die Funktionen sind über den int Befehl auch alle erreichbar (d.h. meine IDT scheint schonmal korrekt zu sein).

Den PIC habe ich folgendermaßen initialisiert:

// Master-PIC initialisieren
outb(0x20, 0x11); // Initialisierungsbefehl fuer den PIC
outb(0x21, 0x20); // Interruptnummer fuer IRQ 0
outb(0x21, 0x04); // An IRQ 2 haengt der Slave
outb(0x21, 0x01); // ICW 4

// Slave-PIC initialisieren
outb(0xa0, 0x11); // Initialisierungsbefehl fuer den PIC
outb(0xa1, 0x28); // Interruptnummer fuer IRQ 8
outb(0xa1, 0x02); // An IRQ 2 haengt der Slave
outb(0xa1, 0x01); // ICW 4

// Interrupts verknüpfen
IDT::SetGate(0x20, _irq0, 0x08, 0x8E);
IDT::SetGate(0x21, _irq1, 0x08, 0x8E);
IDT::SetGate(0x22, _irq2, 0x08, 0x8E);
IDT::SetGate(0x23, _irq3, 0x08, 0x8E);
IDT::SetGate(0x24, _irq4, 0x08, 0x8E);
IDT::SetGate(0x25, _irq5, 0x08, 0x8E);
IDT::SetGate(0x26, _irq6, 0x08, 0x8E);
IDT::SetGate(0x27, _irq7, 0x08, 0x8E);
IDT::SetGate(0x28, _irq8, 0x08, 0x8E);
IDT::SetGate(0x29, _irq9, 0x08, 0x8E);
IDT::SetGate(0x2A, _irq10, 0x08, 0x8E);
IDT::SetGate(0x2B, _irq11, 0x08, 0x8E);
IDT::SetGate(0x2C, _irq12, 0x08, 0x8E);
IDT::SetGate(0x2D, _irq13, 0x08, 0x8E);
IDT::SetGate(0x2E, _irq14, 0x08, 0x8E);
IDT::SetGate(0x2F, _irq15, 0x08, 0x8E);

// Alle IRQs aktivieren (demaskieren)
outb(0x20, 0x0);
outb(0xa0, 0x0);

Anschließend lade ich die IDT und initialisiere dann die Tastatur:
// Tastaturpuffer leeren
while (inb(0x64) & 0x1)
    inb(0x60);

// Warten bis die Tastatur bereit ist, und der Befehlspuffer leer ist
while ((inb(0x64) & 0x2)) {}
outb(0x60, 0xF4);

In meiner _irq1 Prozedur erzeuge ich eine Bildschirmausgabe, sodass ich ja sehen sollte, wenn eine Taste gedrückt wird. Außerdem lade ich mit inb(0x60) den Scancode und setze danach EOI für den IRQ1.

Wenn ich meinen Kernel mit bochs ausführe, dann erscheint zu beginn direkt einmal, dass eine Taste gedrückt wurde, obwohl ich noch gar nichts gedrückt habe. Wenn ich dann weitere Tasten auf der Tastatur drücke passiert nichts. Irgendwann steht dann auch in der bochs Konsole:

00103620000i[KBD  ] internal keyboard buffer full, ignoring scancode.(1e)
00105448000i[KBD  ] internal keyboard buffer full, ignoring scancode.(1f)
00106000000i[KBD  ] internal keyboard buffer full, ignoring scancode.(20)
00106516000i[KBD  ] internal keyboard buffer full, ignoring scancode.(9e)

Es ist mir bald schon peinlich, dass das, woran ich hier scheitere, auf der Tutorialseite mit einem Stern als "einfach" eingestuft wird. Ich hoffe dennoch auf Hilfe und Verständnis für Anfängerfehler.

lg
Developer30
12
Lowlevel-Coding / Re: PIC initialisieren
« am: 02. August 2013, 17:54 »
Oh. Problem hat sich schon erledigt. Ich hab diese Seite übersehen. Hier: http://www.lowlevel.eu/wiki/PIC_Tutorial findet sich ein gutes Beispiel.
Problem gelöst.
13
Lowlevel-Coding / PIC initialisieren
« am: 02. August 2013, 17:40 »
Hallo,

was für Könner wahrscheinlich eine Sache von einer Minute wäre, bringt mich gerade zum grübeln. Ich möchte die beiden PICs initialisieren, damit ich den IRQ1 für Tastaturereignisse benutzen kann. Also habe ich versucht, die Tabelle auf http://www.lowlevel.eu/wiki/Programmable_Interrupt_Controller#Initialisierung in Code umzusetzen:

// master
outb(0x20, 0x10); // Initialisierung einleiten
outb(0x21, 0x04); // IRQ0 soll auf Interrupt 32 sein (4*8)
outb(0x21, 0x04); // Bitmaske

// slave
outb(0xA0, 0x10); // Initialisierung einleiten
outb(0xA1, 0x04); // IRQ0 immernoch auf 32
outb(0xA1, 2);    // Verbindung zum Master

// kein Interrupt maskieren
outb(0x21, 0);
outb(0xA1, 0);

Die Tastatur habe ich folgendermaßen initialisiert:
// Puffer leeren
while (inb(0x64) & 0x1)
inb(0x60);

// Tastatur aktivieren
while((inb(0x64) & 0x2));
outb(0x60, command);

IDT ist auch initialisiert und ich habe eine Funktion für Interrupt 0x21 eingestellt, die über int $0x21 auch aufgerufen wird.
Wenn ich meinen Kernel mit bochs ausführe, dann passiert auf Tastendruck nichts, obwohl ich in meiner IRQ1 Funktion eine Bildschirmausgabe programmiert habe. Über den manuellen Aufruf mit int $0x21 erscheint die Bildschirmausgabe. Meine Vermutung ist jetzt, dass die PIC Controller nicht richtig eingestellt wurden. Kann mir da jemand weiterhelfen?

lg
Developer30

14
Danke für eure Hilfe Kevin und MNemo.. Die linkscript Lösung von MNemo hat das Problem gefixt. Danke :wink:
15
initialiseConstructors() wird schon auch irgendwo aufgerufen?
ja, es wird in der asmKernel.asm aufgerufen, unmittelbar bevor die kernelMain aufgerufen wird.

loader:
  mov esp,0x200000
  push eax
  push ebx
  call initialiseConstructors    ; Konstruktoren aufrufen
  call kernelMain      ; kernelMain aufrufen

Ansonsten könntest du mal versuchen, ein bisschen Debugcode in die Funktion einzubauen, dass du siehst, welche Konstruktoren (falls überhaupt) er aufruft.
Wie kann ich mir das denn am besten ausgeben lassen?

Du kannst auch mal mit objdump/readelf oder so anschauen, ob deine ctors-Section überhaupt einen Inhalt hat und ob das der erwartete ist.
Ich habe noch nie mit objdump gearbeitet (also sorry falls ich da jetzt was falsch verstehe). Ich habe mir mal mit objdump -h kernel.bin alle sections angezeigt.

$ objdump -h kernel.bin
kernel.bin:     Dateiformat elf32-i386

Sektionen:
Idx Name          Größe     VMA       LMA       Datei-Off Ausr.
  0 .text         00000370  00100000  00100000  00001000  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .eh_frame     000001b8  00100370  00100370  00001370  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .init_array   00000004  00100528  00100528  00001528  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  3 .fini_array   00000004  0010052c  0010052c  0000152c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .bss          00000010  00100530  00100530  00001530  2**2
                  ALLOC

Wenn ich das richtig verstanden habe, müsste es doch auch eine .data section geben, wo dann start_ctors und end_ctors drin sein müsste, oder nicht?

16
Hallo Allerseits,

das ganze ist noch Neuland für mich, also habe ich mich an dem Artikel http://www.lowlevel.eu/wiki/C%2B%2B-Kernel_mit_GRUB orientiert. Ich habe alle Anweisungen auf der Seite befolgt und das ganze mal kompiliert und mit bochs ausgeführt. Ich musste feststellen, dass das screen Objekt, was global in der Video.cpp erstellt wird, scheinbar nicht über den Konstruktor initialisiert wurde, weil auf dem Bildschirm nichts passiert. Wenn ich ein Video Objekt hingegen in der kernelMain Funktion erstelle, dann funktioniert die Bildschirmausgabe. Ich weiß nicht, was ich falsch gemacht haben soll. Eigentlich sollten doch alle Konstruktoren von globalen und statischen Objekten mit der initialiseConstructors Funktion aufgerufen werden. Die Startup.cpp sieht bei mir so aus:

typedef void (*constructor)();
 
// Im Linkerskript definiert
extern "C" constructor start_ctors;
extern "C" constructor end_ctors;
 
extern "C" void initialiseConstructors();
 
// Ruft die Konstruktoren für globale/statische Objekte auf
void initialiseConstructors()
{
  for (constructor* i = &start_ctors;i != &end_ctors;++i)
    (*i)();
}

Das einzig Auffällige ist die Warnung, die beim kompilieren erscheint (ich glaube, mit dem Problem hat die Warnung allerdings nicht viel zutun):

Kernel.cpp:8:6: Warnung: unbenutzter Parameter »multiboot_structur« [-Wunused-parameter]

lg
Developer30
Seiten: [1]

Einloggen