Eigenes OS?


  • Mod

    Hat es angesichts der Diskussion über das weitere Vorgehen noch einen Sinn, den jeweils aktuellen Quellcode mal unter die Lupe zu nehmen?

    Da gäbe es zwei Aspekte, wo ich Unterstützung/Zustimmung brauchen könnte:

    1. Ich habe mal versuchsweise einen Paging/Heap-Mechanismus eingebaut, der aber sehr kompliziert ist, also für den ersten Schritt noch vereinfacht werden sollte, und leider noch nicht funktioniert, habe Testroutinen eingebaut, um zu sehen, wo der Code ausflippt: z.Z. beim Umschalten auf das Paging (wahrscheinlich sind Speicheradressen falsch vorgegeben), echte Tüftelei.
      Da könnte sich jemand auf die Dateien ordered_array.h/c, kheap.h/c und paging.h/c konzentrieren und diese aus didaktischen Gründen vereinfachen und in PrettyOS zum Laufen bringen (da beiße ich gerade dran rum und komme nicht wirklich weiter). Ich habe diesen Code mal hochgeschickt, in der Hoffnung, dass mir jemand einen guten Tipp gibt:
      http://www.henkessoft.de/OS_Dev/Downloads/20_paging_heap_problems.zip

    2. s.u. (Circular Queue: füllen, leeren)



  • Erhard Henkes schrieb:

    Da könnte sich jemand auf die Dateien ordered_array.h/c, kheap.h/c und paging.h/c konzentrieren...

    woher ist der code? oder haste alles selbst geschrieben?
    🙂



  • ah, schon gefunden: http://www.jamesmolloy.co.uk/tutorial_html/7.-The Heap.html
    ist die frage, ob da bugs drin sind, oder ob du nachträglich was fehlerhaftes reinbastelt hast. ich würde vorschlagen, du machst sowas wie 'nen unit-test, also ein kleines testprogramm für den heap, das (unter windoofs, mit msvc z.b.) ohne dein OS läuft. dann kannste auch besser debuggen.
    🙂


  • Mod

    @+fricky: Der ganze Code gefällt mir nicht, da er schwierig zu verstehen und vor allem bezüglich paging und heap nicht voneinander unabhängig ist, aber ich habe bisher noch kein besseres Beispiel gefunden, wollte die Mechanismen auf die Schnelle ausprobieren und analysieren, was man für einen ersten Einstieg wirklich benötigt. James Molloy ist einer der Moderatoren und führenden Köpfe bei osdev.net. Sein Code basiert teilweise auf älteren Arbeiten im Rahmen von Bran's Tutorial.

    Die Idee mit dem unit test ist brauchbar.

    Wenn man sti() vor der Paging-Initialisierung anschaltet, kracht es noch früher, für mich momentan nicht nachvollziehbar. 🙄


  • Mod

    zu 2) Ich mache mir momentan Gedanken im Verständnis des Queue-Mechanismus:
    Wie bewegt man die beiden Zeiger Head and Tail am sinnvollsten? Der buffer verändert ja seine inhaltsbedeutende Größe. Tail ist der Eingang und wird vom Keyboard Handler versorgt. Der wandert bei jedem Key Entry Event eins nach "links", so dass die Zeichen in einer Kette angeordnet werden. Nun aber zum Head: Wenn die KeyQueue (KQ) leer ist, sind doch Head und Tail deckungsgleich und der Key an dieser Stelle wird auf ??? gesetzt. Man kann ja prüfen ob Head und Tail verschieden sind, wenn nein ist die KQ leer (Head minus Tail == 0), wenn ja, stehen Head minus Tail Zeichen drinnen. Sobald Zeichen rein kommen, wandern Head und Tail auseinander, Tail nach links, Head bleibt stehen. Sobald eine "Anwendung" ein Zeichen abholt, wandert Head ebenfalls eins nach links. Habe so etwas noch nie gebaut, daher die Frage, ob das so stimmt. man muss ja noch den Circular-Mechanismus einbauen: Bei Zeiger < KEYQUEUE springt man auf KEYQUEUE+KQSIZE-1, richtig?

    Nun zu den "Zeichen" in der KQ: Ein Zeichen besteht ja aus dem ASCII-Zeichen plus Flags (Sonderzeichen), d.h. pro Zeichen müsste man eigentlich mindestens zwei Byte ablegen, eins enthält das ASCII-Zeichen (da könnte man Shift auch gleich verarbeiten, also im Flag weglassen) und eins die Zusatz-Info, z.B. (Shift links/rechts), ALT/ALT Gr, CTRL links/rechts, usw. bzw. Kombinationen davon. (Bisher analysiere ich im Handler ja nur die Shift-Taste, rechts/links noch gleich).

    Ich hoffe, ihr versteht, was ich da schreibe. 😕
    Ich verstehe momentan nicht wie BIOS/BDA das machen, weil dort ja die Sondertasten-Bits stehen. Zu jedem Tastenanschlag gehört ja je nach design entweder nur eine Taste (shift/non-shift) oder eine Kombination aus Sondertasten und Taste (vielleicht zu kompliziert). Momentan kommen wir an ALT Gr aber nicht ran.



  • Erhard Henkes schrieb:

    Der ganze Code gefällt mir nicht, da er schwierig zu verstehen und vor allem bezüglich paging und heap nicht voneinander unabhängig ist...

    naja, memory-management ist nie 'ne einfache sache. am anfang liefert der kernel ein paar aufeinanderfolgende speicherseiten und der heap-manager ist dazu da, diese relativ grossen speicherbereich in kleinere häppchen zu verhackstücken. sind alle seiten aufgebraucht, dann müssen vom kernel neue seiten angefordert werden, die hinten angehängt werden. trennen kannste das insofern, dass der heap-manager (testweise) mit einem fixen block arbeitet. also,
    baustelle-1, kernel: seitenverwaltung, paging, virtual memory.
    baustelle-2, heap-manager: einen beliebig grossen, zusammenhängenden speicherbereich mit malloc/realloc/free zu zerstückeln.
    baustelle-3: zusammenspiel beider subsysteme.
    wichtig ist z.b. auch, dass es mehrere instanzen des heap-managers geben kann, so dass jeder prozess seinen eigenen heap bekommt. auch im kernel sollte mindestens eine instanz des heap-managers da sein, damit kernel-komponenten nicht für jeden kleinkram eine ganze speicherseite verbraten müssen.
    🙂


  • Mod

    Danke für die Ideen.

    ..



  • Erhard Henkes schrieb:

    zu 2) Ich mache mir momentan Gedanken im Verständnis des Queue-Mechanismus:
    Wie bewegt man die beiden Zeiger Head and Tail am sinnvollsten?

    http://en.wikipedia.org/wiki/Circular_buffer
    (lies ab 'difficulties')
    🙂


  • Mod

    +fricky schrieb:

    Erhard Henkes schrieb:

    zu 2) Ich mache mir momentan Gedanken im Verständnis des Queue-Mechanismus:
    Wie bewegt man die beiden Zeiger Head and Tail am sinnvollsten?

    http://en.wikipedia.org/wiki/Circular_buffer
    (lies ab 'difficulties')
    🙂

    Danke für den Hinweis. Kontrolle der "Read/Write Counts" gefällt mir am besten, weil der Zirkular-Mechanismus nicht gestört wird.

    (write_count - read_count) always yields the number of items placed in the buffer and not yet retrieved.

    Das macht Sinn, die beiden Variablen kommen in meine allgemeine ODA(OS Data Area)-Struktur dazu. Dann hat man auch eine einfache Kontrolle über Schreiben/Lesen/Buffer Full bzw. Overrun in der Queue.



  • Erhard Henkes schrieb:

    Schaltet man sti() vorher ein, so kracht es sofort. Man sieht keine einzige Meldung

    Dann prüf mal wo genau es kracht:

    void paging_install()
    {
     ULONG mem_end_page = PHYSICAL_MEMORY;
     nframes = mem_end_page/PAGESIZE;
     frames  = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes)); // <- hier?
     k_memset(frames, 0, INDEX_FROM_BIT(nframes));       // <- oder hier?
    (...)
    

    Oder bereits vor dem Aufruf von "paging_install ()" (i.S.v. wenn sti() ausgeführt wird)?



  • @+fricky:

    auch "stinknormale" c-anwendungen lassen sich bauen, wenn man die anwendungen ereignisgesteuert macht.
    wie die tastatureingabe beim "keyget" ankommt hat damit überhaupt nichts zu tun.

    in jeder anwendung aber dieses polling zu haben ist, meiner meinung nach, einfach nicht sinnvoll.

    Eine Speicherverwaltung zu bauen ist aus meiner Sicht noch viel zu früh.

    Lieber einen Scheduler und mehrere Anwendungen.

    jenz


  • Mod

    Eine Speicherverwaltung zu bauen ist aus meiner Sicht noch viel zu früh.
    Lieber einen Scheduler und mehrere Anwendungen.

    Noch liegt nichts fest, bin nur am Austesten. Ich habe mich bei der Reihenfolge des Aufbaus von folgender Aussage James Molloy's inspirieren lassen:

    Dynamic memory allocation is one of the few things that it is very difficult to do without. Without it, you would have to specify an absolute maximum number of processes running (static array of pids), you would have to statically give the size of every buffer - Generally making your OS lacklustre and woefully inefficient.

    "glanzlos und beklagenswert ineffizient", das hört sich nicht gerade anziehend an. 😃
    Daher schlage ich mich im Hintergrund mit dem Pagigng/Heap-Mechanismus von James Molley herum. Das muss auch alles noch simplifiziert werden, derart unverständlicher Code kommt mir in kein Tutorial.


  • Mod

    +gjm+ schrieb:

    Erhard Henkes schrieb:

    Schaltet man sti() vorher ein, so kracht es sofort. Man sieht keine einzige Meldung

    Dann prüf mal wo genau es kracht:

    void paging_install()
    {
     ULONG mem_end_page = PHYSICAL_MEMORY;
     nframes = mem_end_page/PAGESIZE;
     frames  = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes)); // <- hier?
     k_memset(frames, 0, INDEX_FROM_BIT(nframes));       // <- oder hier?
    (...)
    

    Oder bereits vor dem Aufruf von "paging_install ()" (i.S.v. wenn sti() ausgeführt wird)?

    Guter Vorschlag.

    TEST:
    ckernel:

    #include "os.h"
    
    int main()
    {
        k_clear_screen();
    
        // GDT, IDT, ISRS, IRQ, timer, keyboard
        gdt_install();
        idt_install();
        isrs_install();
        irq_install();
        timer_install();
        keyboard_install();
        sti();
        paging_install(); //TEST
    //...
    

    ..

    Das ganze ist einfach ein riesiger Wirrwarr, macht so als Tutorial keinen Sinn, weil niemand irgendetwas nachverfolgen und damit experimentieren kann. Ich stehe selbst wie vor einem Berg und weiß noch nicht, wie ich den Tunnel bohren soll.

    Wenn ich so auf kmalloc(...) schaue, frage ich mich gerade, wo eigentlich der heap erzeugt wird, denn vorher ist kheap = 0.

    ..


  • Mod

    TEST1:

    #include "os.h"
    
    int main()
    {
        k_clear_screen();
    
        // GDT, IDT, ISRS, IRQ, timer, keyboard
        gdt_install();
        idt_install();
        isrs_install();
        irq_install();
        timer_install();
        keyboard_install();
        sti();
        k_memset(44880, 0, 512);
        //paging_install(); //TEST
    

    ergibt reset.

    #include "os.h"
    
    int main()
    {
        k_clear_screen();
    
        // GDT, IDT, ISRS, IRQ, timer, keyboard
        gdt_install();
        idt_install();
        isrs_install();
        irq_install();
        timer_install();
        keyboard_install();
        //sti();
        k_memset(44880, 0, 512);
        //paging_install(); //TEST
    
        set_cursor(0,0);
        printformat("   ************************************************\n");
    	printformat("   *          Welcome to PrettyOS 0.06            *\n");
    	printformat("   *          Paging is activated                 *\n");
    	printformat("   ************************************************\n");
    

    läuft durch bis zum Titel-Ausdruck.
    Analyse passt also.
    Jetzt brauchen wir die Diagnose und das Heilmittel.


  • Mod

    Ich habe mal

    sti();
        k_memset(65536, 0, 512);
        //paging_install(); //TEST
    

    probiert, also mal 65536 (10000h) als Ziel. Das geht ohne Reset.
    Also sollte es doch an diesem 44880 (AF50h) liegen. Liege ich da mit meinen Gedanken richtig?
    Versuche gerade nachzuvollziehen, warum bei der Paging-Install-Routine gerade 44880 heraus kommt.

    Diese Bitset-Geschichte (vielleicht kann man das einfacher machen) läuft wie folgt:

    INDEX_FROM_BIT(nframes) 
    
    // Macros used in the bitset algorithms.
    #define INDEX_FROM_BIT(a)   (a/(8*4))
    #define OFFSET_FROM_BIT(a)  (a%(8*4))
    

    Also INDEX_FROM_BIT(16384) ==> (16384/(8*4)) = 512



  • jenz schrieb:

    @+fricky:
    auch "stinknormale" c-anwendungen lassen sich bauen, wenn man die anwendungen ereignisgesteuert macht.
    wie die tastatureingabe beim "keyget" ankommt hat damit überhaupt nichts zu tun.

    also willst du, dass jede anwendung event-handler (für key events) implementieren muss, oder wie meinst du das?

    jenz schrieb:

    in jeder anwendung aber dieses polling zu haben ist, meiner meinung nach, einfach nicht sinnvoll.

    polling in dem sinn, dass die cpu, wegen vieler missglückter abfragen, zyklen verbrät, kann ja schon durch eine blocking 'getchar' umgangen werden (oder durch mein beispiel von weiter oben).
    🙂



  • Erhard Henkes schrieb:

    Wenn ich so auf kmalloc(...) schaue, frage ich mich gerade, wo eigentlich der heap erzeugt wird, denn vorher ist kheap = 0.

    da gibt's doch 'ne funktion 'create_heap'. die musste natürlich vorher aufrufen.
    🙂


  • Mod

    Diese Message Geschichten sind eher typisch für Mini Kernels wie das bedeutungslose (?) aber "elegante" Minix von Tanenbaum. Wie gesagt, ich bin diesbezüglich noch völlig locker.

    Momentan machen mich einfach die C-Basics fertig. Als C++ler bin ich ich echt nicht gewohnt, so "tief unten" zu wühlen, aber ich finde gerade diese herausforderung, alles selbst aufbauen zu müssen, total interessant. Ist alles nur eine Frage der Zeit, bis das klappt.

    Aber ob das noch tutorial-tauglich ist, was ich da treibe, da bin ich nicht mehr sicher. So auf gar keinen Fall. Ein Zwischenverweis auf James Molley's Tutorial (er lädt mit Grubs und verwendet im Programm externe Daten aus dem Linker Skript, igitt) und weiter machen / modifizieren, wo er aufhört, macht IMHO keinen Sinn.



  • "frames" ist seltsamerweise zu klein, was heißt, daß der Aufruf von

    k_memset(frames, 0, INDEX_FROM_BIT(nframes));
    

    wohl einen Teil des Kernels überschrieben hat. Lt. Quelltext hätte "frames" aber nach Aufruf von

    frames = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes));
    

    0x300000 sein müssen:

    //kheap.c
    
    ULONG kmalloc(ULONG sz)
    {
     return kmalloc_int(sz, 0, 0);
    }
    
    ULONG kmalloc_int(ULONG sz, int align, ULONG *phys)
    {
      if (kheap != 0) // "kheap" ist Null beim ersten Aufruf
      {
    (...)
      }
      else
      {               // "align" ist auch Null
       if (align == 1 && (placement_address & 0xFFFFF000) )
       {
    (...)
       }
       if (phys)      // "phys" auch
       {
       *phys = placement_address;
       }
    // somit wird "placement_address" zurückgegeben
       ULONG tmp = placement_address;
       placement_address += sz;
       return tmp;
      }
    }
    

    Und "placement_address" ist:

    //kheap.h
    (...)
    heap_t* kheap = 0;
    (...)
    ULONG end               = 0x300000;    // 3 MB TODO???
    ULONG placement_address = (ULONG)&end; // <- die Adresse von "end"?????
    

    Hoffentlich hilft das weiter.


  • Mod

    @+gjm+: Danke für die Analyse, kannst Du Dir den aktuellen Code nochmals anschauen?

    Da waren leider doch noch einige plötzlich aufpoppende Fehler mit memset() anstelle k_memset in ordered_array usw., aber dennoch klappt es noch nicht richtig. Habe auch in den headern os.h, ... noch etwas Ordnung (hoffentlich) geschafft.

    Ich schiebe den aktuellen Code mal hoch, vielleicht hat jemand die entscheidende Idee zum Durchblick. Vor lauter blöden Adressen blicke ich nicht mehr durch.
    create_heap() hilft auch noch nicht. Bin nicht völlig sicher, ob das in ckernel.c sein muss. Keine Ahnung, wo der heap momentan erzeugt wird.

    Sehe vor lauter Wald die Bäume nicht mehr, aber den Code dürfte ich jetzt soweit funktionsfähig haben. Könnte sich das bitte mal jemand anschauen (fehlen nur noch die richtigen Parameter, sicher bin ich aber noch nicht)? 🙄
    http://www.henkessoft.de/OS_Dev/Downloads/20_analyze_failure.zip

    EDIT1: hier sieht die frames Anzahl (mit createheap(0x300000,...) z.B. 3674124) nun besser aus.
    es läuft ohne sti() durch bis zum Umschalten auf Paging, dann kommt der reset, kann noch an falschen Parametern liegen:
    http://www.henkessoft.de/OS_Dev/Bilder/Fehlersuche_PAGING_HEAP.PNG

    EDIT2: das Problem liegt in create_heap(...)
    Da ist etwas im hinteren Teil instabil. Auch mit Kontroll-Prints passieren da merkwürdige Sachen auf dem Bildschirm, noch dazu nicht gleich reproduzierbar.
    ..

    heap in create_heap(...) 0000B1D0h
    heap->index in create_heap(...) 00200000h
    header_t_less_than in create_heap(...) 0000A90Ch
    start in create_heap(...) 00280000h
    start ... after alignment check 00281000h

    Absturz?

    Manchmal kommt auch noch die nächste Zeile. ???
    Nach der letzten Ausgabe springt der Cursor nach (0,0)! keine Ahnung warum?
    Dann erfolgt Reset.

    Ohne sti() bekommt man mehr Infos (s.u. seaprater Post)

    Bitte um weitere Unterstützung, damit wir das Thema didaktisch angehen können.

    Ich werde mich mal zur Ablenkung auf die Key Queue als nächste Aufgabe konzentrieren.

    Diesen Paging/Heap Mist werde ich etwas schieben. Dieser verschachtelte Code mit den kreuz und quer verteilten Parametern nervt mich langsam.

    Der Code müsste für ein Tutorial entflochten und klar strukturiert werden.
    Vielleicht kennt/hat jemand etwas Besseres?

    Problemliste:
    - Beep() geht nicht (speaker)
    - Paging/Heap zum Laufen bringen

    Kurzfristige Taskliste:
    - KeyQueue aufbauen (als ersten Schritt kann man die Daten ja über eine Auswerte-Funktion in ckernel.c abholen und darstellen)
    - Paging/Heap entflechten (erst Heap und Demo, dann Paging für Multitasking)

    Auf jeden Fall danke an alle, die mich unterstützen.


Anmelden zum Antworten