Autor Thema: Os, was macht man wann und wie???  (Gelesen 8530 mal)

sov21

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« am: 26. March 2005, 00:42 »
Hallo,
ich habe schon etwas rumprobiert mit dem thema Os-progrmming.
Aber immer noch kein Durchblick.
Also meine Frage(n), ob ich das so richtig sehe:

Zu erst schreibt man einen bootloader und befindet sich im 16bit Modus (Realmode). Der Bootloader darf nicht größer als 512 byte sein?!
Dieser läd den Kernel in den Speicher und springt hinein?!
Wenn der Kernel nun in C geproggt ist, ist er dann automatisch 32bit?
Also muß ich vorher in den PM schalten, oder kann ich das in dem C-Kernel selbst machen??
Wie groß darf den dieser Kernel werden?? Kann es da Probs geben, wenn man die ganze zeit Module mit dem Kernel zusammenlinkt und dieser immer weiter wächst?

Wie ist das mit dem FAT 12 - Bootloader? Der läd doch einen kernel aus dem Dateisystem eine Diskette. Nur wie bekomme ich den bootloader in den bootsektor der diskette, ohne das Dateisystem zu zerschießen?
Wenn ich wie im forum vorgeschlagen den Rawwrite nehme, kann man denn dann die diskette in WinXP noch lesen und den Kernel rein kopieren?
Weil wenn das nicht mehr geht, was bringt mir dann das laden des kernels aus dem Dateisystem wenn ich eh Rawrite benötige?!

Ihr seht schon tausend Fragen.
Weiter:
Also wenn ich nun im PM in meinem C-Kernel bin.
Dann muß ich die Interrupts irgendwie umlenken auf die IDT oder so.
Wo muß ich denn die IDT anlegen? Im bootloader vor dem PM oder kann ich das auch im PM in meinem C kernel irgendwie mit einer Funktion oder so anlegen?
Wann muß ich den PIC umproggen? Vor erstellen der IDT und ISR oder danach?
Wie ist das mit dem A20-Gate? Das habe ich zu zeit im C-kernel nach betreten des PM direkt erledigt.

Vielen Dank fürs lesen und ich hoffe auf viele Tipps und Hilfe :-(
Bin etwas verwirrt mit dem ganzen.
Gruß sov21

DarkThing

  • Beiträge: 652
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 26. March 2005, 13:40 »
Direkt nach dem Start befindet sich der PC im Real Mode (also 16bit). Im Bootsector sollte man (man muss aber nicht) in den Protected Mode umschalten. Danach ist man im 32-Bit Modus, unabhängig von der Programmiersprache. Wenn der Bootsector Fat-Kompatibel sein soll, muss man sich an ein paar Regeln halten (siehe Tee Jays Fat Tutorial).
Der Bootsector ist wie der Name sagt ein Sektor groß und ein Sektor enstspricht 512 Bytes.
Im PM darf man keine BIOS Interrupts verwenden, d.h. man muss Funktionen für Tastatur, Bildschirm, Diskette, ... selber schreiben. Die IDT hängt da auch mit drin, ist aber komplizierter zu erklären.

Wenn du noch irgendwelche Fragem hast, kannst du gerne fragen  :wink:

sov21

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 27. March 2005, 14:08 »
Danke für die Antwort.
Ein paar fragen sind aber leider immernoch offen.
Also das in den PM schalten, kann man nicht im C-Kernel machen??
Wie ist das mit der Reihenfolge mit der IDT und dem PIC??
Für was ist es von Vorteil einen FAT 12 fähigen Bootloader zu haben???
Gruß sov21

zacK

  • Beiträge: 216
    • Profil anzeigen
    • http://www.domae.ch
Gespeichert
« Antwort #3 am: 27. March 2005, 15:49 »
du kannst auch in c in den pm schalten... du musst ihn einfach in 16bit compilieren...  dann brauchst du 2 kernel einen 16 bit der in 32bit schaltet und dann einen 32bit für das weitere..

zuerst programmierst du die pics und dann lädtst du die idt....

einen fat12 fähigen bootsector hat viele vorteile..

1. du brauchst dich nicht darum zu kümmern wenn der kernel wächst
2. du kannst später dateien ab der diskette laden
3. rawrite stinkt mit der zeit (*sorry*)
4. .....

sov21

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 27. March 2005, 17:18 »
Cool, jetzt weiß ich wieder etwas mehr.
Nur, wie ist das, wieso kann ich mir mit dem FAT12, den Rawwrite ersparen, und wie?? Weil den FAT12-fähigen Bootloader muß ich doch auch in den Bootsektor der Diskette bekommen. Brauche ich dafür kein Rawwrite?? Oder wie geht das?
Wenn ich zB den FAT fähigen Bootloader von TJ nehme, ist dann wirklich die Größe des Kernels egal??
Also egal wieviele Sektoren der benötigt??
Wenn ich einen 16 bit kernel und einen 32 bit kernel in C habe, kann ich dann von dem 16bit in den 32er nach dem Übergang in den PM einfach per Funktionsaufruf wechseln? Oder muß ich da irgenwas beachten??
Ich habe schon mal in C eine Datei geschrieben, die den PIC anspricht und am Ende wie in dem Tut hier im Forum die Ints ausschaltet. Aber für den IDT darf ich die doch nicht ausschalten, sondern muß die doch irgendwie umlegen oder so?!
Danke für die Antworten :-)
Gruß sov21

zacK

  • Beiträge: 216
    • Profil anzeigen
    • http://www.domae.ch
Gespeichert
« Antwort #5 am: 27. March 2005, 18:02 »
joa, für den bootsector.. aber dann kanst du den kernel einfach per explorer auf die diskette mechn... der kernel darf nätürlich nicht grösser sein als die disketten grösse - fat-tabellen - rootdirectory - bootsector...

also am besten machst du es so wi im tutorial von t-jay (c-tutorial)...

einen kernel der aus drei dateien besteht.
kernel16.asm <- schaltet in pm, vesa, a20, etc...
kernel32.asm <- ruft die main methode vom c-kernel auf
kernel.c         <- der eigendliche kernel...

am besten lädts du mal ein paar quelltexte herunter und schaust wie wir es so gelöst haben... durch lesen von quelltexte habe ich fast am meisten gelernt...

pic & idt:

du remapst die pics zb auf interrupts 32 - 48 oder so... dann schaltest du die irq's aus (maskieren)... anschliessend lädtst du di idt. erst dann kannst du die irq's und interrupts wieder aktivieren...

achtung: sobald du sie aktivierst, wird innert kürze den irq0 ausgelöst -> timer... du solltest ne funktion bereitstellen die dann ausgeführt wird. ansonsten hast du ein problem.. ausser du maskierst ihn... der irq0 geht zb. auf den isr 32... dort trägst du die adresse einer asm routine ein..

sov21

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 27. March 2005, 19:40 »
Cool,
das hört sich gut an.
Das mit der Idt gehe ich später an.
Erst möchte ich eine gute Lösung für Loader + Kernel.
Kann man die 16bit Asm auch als 16bit C machen irgendwie, oder geht sowas wie Pm aktivieren nur in asm und nicht über Ports??

DarkThing

  • Beiträge: 652
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 27. March 2005, 21:05 »
Vieles kann man auch in C machen, aber nicht alles. PM dürfte man nicht mit C schaffen (außer per Inline-Assembler). Aber das meiste andere sollte man über die Ports schaffen.

@IDT
Ich hab für jeden Interrupt die gleiche Funktion. Wenn die aufgerufen wird nehm ich mir die Interrupt-Nummer und suche in nem Array nach einem Function-Pointer auf die eigentliche Funktion. Das ist in sofern sinnvoll, dass man zur Laufzeit diese Function Pointer problemlos ändern kann.

sov21

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 27. March 2005, 21:25 »
Alles klar.
Vielen Dank für eure Hilfe.
Werde mich dann demnächst bestimmt wegen diesen IDT und PIC usw. mal wieder melden müssen :-)
Gruß sov21

zacK

  • Beiträge: 216
    • Profil anzeigen
    • http://www.domae.ch
Gespeichert
« Antwort #9 am: 27. March 2005, 22:42 »
@DarkThing:
stimmt das ist klever!. muss ich auch machn... ;)

DarkThing

  • Beiträge: 652
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 28. March 2005, 10:08 »
Bei osdever.net gibt es ein Tutorial darüber (das heißt Bran's Kernel Dev oder so). Kann ich allen die sich mit IDT & Co. beschäftigen wollen empfehlen.

PS: Bin jetz 5 Tage in Urlaub  8)

joachim_neu

  • Beiträge: 1 228
    • Profil anzeigen
    • http://www.joachim-neu.de
Gespeichert
« Antwort #11 am: 28. March 2005, 10:32 »
Zitat von: DarkThing
Vieles kann man auch in C machen, aber nicht alles. PM dürfte man nicht mit C schaffen (außer per Inline-Assembler). Aber das meiste andere sollte man über die Ports schaffen.

@IDT
Ich hab für jeden Interrupt die gleiche Funktion. Wenn die aufgerufen wird nehm ich mir die Interrupt-Nummer und suche in nem Array nach einem Function-Pointer auf die eigentliche Funktion. Das ist in sofern sinnvoll, dass man zur Laufzeit diese Function Pointer problemlos ändern kann.


nette methode, aber ich schreibe lieber meine IDT um, kann man auch zur laufzeit machen, aber die adresse auf die neue funktion richtig finden dürfte schwer werden, weil du keine labels mehr hast...
http://www.joachim-neu.de | http://www.orbitalpirates.de | http://www.middleageworld.de

System: 256 RAM, GeForce 2 MX 400, AMD Athlon XP 1600+, Windows XP, 1x Diskette, 1x DVD-ROM, 1x CD-R(W) Brenner,...

DarkThing

  • Beiträge: 652
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 03. April 2005, 13:56 »
Ich hab mal den Code aus Bran's Kernel Dev kopiert:


/* bkerndev - Bran's Kernel Development Tutorial
*  By:   Brandon F. (friesenb@gmail.com)
*  Desc: Interrupt Descriptor Table management
*
*  Notes: No warranty expressed or implied. Use at own risk. */
#include <system.h>

/* Defines an IDT entry */
struct idt_entry
{
    unsigned short base_lo;
    unsigned short sel;
    unsigned char always0;
    unsigned char flags;
    unsigned short base_hi;
} __attribute__((packed));

struct idt_ptr
{
    unsigned short limit;
    unsigned int base;
} __attribute__((packed));

/* Declare an IDT of 256 entries. Although we will only use the
*  first 32 entries in this tutorial, the rest exists as a bit
*  of a trap. If any undefined IDT entry is hit, it normally
*  will cause an "Unhandled Interrupt" exception. Any descriptor
*  for which the 'presence' bit is cleared (0) will generate an
*  "Unhandled Interrupt" exception */
struct idt_entry idt[256];
struct idt_ptr idtp;

/* This exists in 'start.asm', and is used to load our IDT */
extern void idt_load();

/* Use this function to set an entry in the IDT. Alot simpler
*  than twiddling with the GDT ;) */
void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags)
{
    /* The interrupt routine's base address */
    idt[num].base_lo = (base & 0xFFFF);
    idt[num].base_hi = (base >> 16) & 0xFFFF;

    /* The segment or 'selector' that this IDT entry will use
    *  is set here, along with any access flags */
    idt[num].sel = sel;
    idt[num].always0 = 0;
    idt[num].flags = flags;
}

/* Installs the IDT */
void idt_install()
{
    /* Sets the special IDT pointer up, just like in 'gdt.c' */
    idtp.limit = (sizeof (struct idt_entry) * 256) - 1;
    idtp.base = &idt;

    /* Clear out the entire IDT, initializing it to zeros */
    memset(&idt, 0, sizeof(struct idt_entry) * 256);

    /* Add any new ISRs to the IDT here using idt_set_gate */



    /* Points the processor's internal register to the new IDT */
    idt_load();
}


Der interessante Teil hier ist die Funktion idt_set_gate!

Noch ein Beispiel:

void isrs_install()
{
    idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E);
    idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E);
    idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E);
    idt_set_gate(3, (unsigned)isr3, 0x08, 0x8E);

    ...                         /* Fill in the rest of these ISRs here */

    idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E);
    idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E);
}


Der zweite Parameter ist einfach nur der Name der Funktion.

 

Einloggen