Eigenes OS?


  • Mod

    Danke für den Link, aber ich möchte es mit einer Datenstruktur analog BDA probieren, sieht momentan so aus:
    os.h:

    /* This defines the operatings system common data area */
    
    #define KQSIZE    100 // size of key queue
    
    typedef struct oda
    {
        // Hardware Data
        //...
    
        // Key Queue
        UCHAR  KEYQUEUE[KQSIZE];   // circular queue buffer
        UCHAR* pHeadKQ;            // pointer to the head of valid data
        UCHAR* pTailKQ;            // pointer to the tail of valid data
        UCHAR  KQ_count_read;      // number of data read from queue buffer
        UCHAR  KQ_count_write;     // number of data put into queue buffer
    }oda_t;
    
    // operatings system common data area
    oda_t ODA;
    extern oda_t* pODA;
    

    util.c (später vielleicht os.c):

    oda_t* pODA = &ODA;
    
    void initODA()
    {
        int i;
        for(i=0;i<KQSIZE;++i)
           pODA->KEYQUEUE[i]=0;          // circular queue buffer
        pODA->pHeadKQ = pODA->KEYQUEUE;  // pointer to the head of valid data
        pODA->pTailKQ = pODA->KEYQUEUE;  // pointer to the tail of valid data
        pODA->KQ_count_read  = 0;        // number of data read from queue buffer
        pODA->KQ_count_write = 0;        // number of data put into queue buffer
    }
    

    keyboard.c

    void keyboard_handler(struct regs* r)
    {
       UCHAR KEY = ScanToASCII();
       if(KEY)
       {
         *(pODA->pTailKQ) = KEY;
         ++(pODA->KQ_count_write);
    
           if(pODA->pTailKQ > pODA->KEYQUEUE)
           {
               --pODA->pTailKQ;
           }
           if(pODA->pTailKQ == pODA->KEYQUEUE)
           {
               pODA->pTailKQ = (pODA->KEYQUEUE)+KQSIZE-1;
           }
       }
       //...
    }
    

    Test in ckernel.c:

    //...
        initODA();
        printformat("KQ: %x TAIL: %x HEAD: %x", pODA->KEYQUEUE, pODA->pTailKQ, pODA->pHeadKQ);
    
        settextcolor(2,0);
    
    	int y=6;
    	while(TRUE)
    	{
    	    sleepSeconds(10);
    	    if(y>24) y=24;
    	    set_cursor(0,++y);
    	    printformat(" 10 sec: ");
    	    printformat("TAIL: %x HEAD: %x WRITE: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write);
    	    printformat("TAILCONTENT: %c %i HEADCONTENT: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
    	};
    

    ************************************************
    * Welcome to PrettyOS 0.06 *
    * Paging is activated *
    ************************************************
    KQ: 0000A1A4h TAIL: 0000A1A4h HEAD: 0000A1A4h

    10 sec: TAIL: A1A4h HEAD: A1A4h WRITE: 0 TAILCONTENT: 0 HEADCONTENT:
    10 sec: TAIL: A207h HEAD: A1A4h WRITE: 1 TAILCONTENT: 0 HEADCONTENT: a
    10 sec: TAIL: A206h HEAD: A1A4h WRITE: 2 TAILCONTENT: 0 HEADCONTENT: a
    10 sec: TAIL: A205h HEAD: A1A4h WRITE: 3 TAILCONTENT: 0 HEADCONTENT: a
    10 sec: TAIL: A204h HEAD: A1A4h WRITE: 4 TAILCONTENT: 0 HEADCONTENT: a
    10 sec: TAIL: A1FEh HEAD: A1A4h WRITE: 109 TAILCONTENT: g 103 HEADCONTE
    NT: a 97

    0xA207 = 0xA1A4 + 0x64 (KQSIZE) - 1
    passt also alles. Den Tasten-Release (KEY == 0) habe ich unterdrückt, so dass nur ein Zeichen pro Tastenanschlag in die KQ gelangt.

    Ich möchte diesen Mechanismus komplett selbst durchziehen, weil ich das derart low-level noch nicht gemacht habe, bin durch die Standard Template Library verhätschelt. 😃

    Über Lesen aus der KQ und Interrupts habe ich mir noch keine Gedanken gemacht.
    Wie geht man mit einem buffer full, also (pODA->KQ_count_write - pODA->KQ_count_read)>100 um. Da ich die Zähler momentan leichtsinnig in UCHAR definiert habe, kommt es auch noch zu einem Überlauf. 😃 Das lässt sich sicher durch ULONG in den Griff bekommen, aber prinzipiell ist das Problem dadurch nur in die weite Ferne geschoben. Es soll ja Leute geben, die ihren Rechner nie ausschalten. Bei PrettyOS ist das fast garantiert. 😉

    Wo sollte das Lese-Programm, also das alte:

    restore_cursor();
       switch(KEY)
       {
           case KINS:
               break;
           case KDEL:
               move_cursor_right();
               putch('\b'); //BACKSPACE
               break;
           case KHOME:
               move_cursor_home();
               break;
           case KEND:
               move_cursor_end();
               break;
           case KPGUP:
               break;
           case KPGDN:
               break;
           case KLEFT:
               move_cursor_left();
               break;
           case KUP:
               break;
           case KDOWN:
               break;
           case KRIGHT:
               move_cursor_right();
               break;
           default:
               printformat("%c",KEY); // the ASCII character
               break;
       }
       save_cursor();
    

    nun eigentlich hin? Der User will doch Zahlen und Buchstaben sehen, wenn er tippt. 😃 Zumindest als Demo.
    Soll ich das als getchar() in keyboard.c realisieren und in ckernel.c mal als demo in der while-Schleife (klares "Polling") laufen lassen oder habt ihr bessere Ideen?


  • Mod

    Ich habe das zunächst als k_checkKQ_and_print_char() umgesetzt, um didaktisch an unsere bisherige - von Nobuo T kritisierte - "Schreibmaschine" in keyboard_handler(...) anzuknüpfen.

    Test in ckernel:

    UINT c=0;
    	while(TRUE)
    	{
    	  if( k_checkKQ_and_print_char() )
    	  {
    	    ++c;
    	    if(c>79)
    	    {
    	      c=0;
    	      settextcolor(4,0);
    	      printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
              printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
              settextcolor(2,0);
    	    }
    	  }
    	}
    
    jkdfhsdjkhgksjhkjdhkjdfshjkdsfhgjkhjghdfjkghjkdfhgdjkfhkdjfhgkdjfhgkjdfhjkdfhgjk
    dfhgjkdfhksdfhksdahfksdajhfkjsdhfksdjhfksdajhfasdkhfjkasdhfkasjdfhkjasdhfksladjh
    faskdjlhfkjhsadkjfhkjasdhfjkasdfhkajsdhfjkasdfhkjasdhfjkasdhfjkasdhfjkasdhfjkasd
    hfjkhfjkasdhfjksdhfkjahhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
    hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
    hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
    hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
    jjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkKKKKKKKKKKKKKLAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    T: 0000A2DAh H: 0000A2DAh WRITE: 640 Read: 640 *T: j 106 *H: j 106
    T: 0000A2EDh H: 0000A2EDh WRITE: 720 Read: 720 *T: A 65 *H: A 65
    

    Test und Reaktion (welche?) auf BufferFull/Overrun fehlt noch.
    Die Pfeiltasten links/rechts kommen nicht mehr durch.
    Was man wirklich mit den Infos in der KeyQueue machen will, hängt sehr von der konkreten Anwendung ab. Ich frage mich momentan, wie man mit den Sondertasten sinnvoll umgehen sollte. Als Flags in der ODA wie bei der BDA machen sie keinen Sinn, weil man nicht weiß, zu welchem Zeichen sie gehören. Aber das lässt sich alles leicht anpassen. Vielleicht hat jemand eine glänzende Idee oder gute Erfahrungen mit eigenen OS.

    Ich schieb das Programm oben mal hoch, wenn jemand mit dem Code spielen will:
    http://www.henkessoft.de/OS_Dev/Downloads/22a.zip

    Baut man eine Verzögerungsschleife ein, so kommt Schreiben/Lesen so ab 100 Millisekunden (Warteschleife für ms habe ich nun in timer.c ergänzt) aus dem Gleichklang: http://www.henkessoft.de/OS_Dev/Downloads/22b.zip

    jksdghkdfjhgkskdfjhgkjsdfhgkjsdfhgskjdfhkhjhgdfjkhgdfkjhgkjdfhgkjdfhgkdfjhgkjdfh
    gkfdhgkdfhgkdfhgkdfhgkdfhgkdfjhgkdfhgkdfhgkfhkjdshgkjsdfjjjjjjjjjjjjjjjjjjjjjjjj
    jjjjJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAh WRITE: 662 Read: 640 *T: A 65 *H: A 65
    T: 0000A2E0h H: 0000A30Dh WRITE: 765 Read: 720 *T: A 65 *H: A 65
    

    Bleiben die Fragen, wie groß muss KQ sein und wie geht man mit einem Overrun um? (früher hat es da gepiepst 😃 ).


  • Mod

    Bezüglich der Interpretation von Scancodes habe ich folgende interessante Gliederung gefunden:
    http://www.toasteros.net/
    ..



  • Erhard Henkes schrieb:

    Bleiben die Fragen, wie groß muss KQ sein und wie geht man mit einem Overrun um?

    einfach das älteste zeichen überschreiben (overrun ignorieren). daten von der tastatur kannste als veraltet ansehen, wenn lange keiner drauf zugegriffen hat. der buffer kann auch ziemlich klein sein.
    🙂



  • +fricky schrieb:

    der buffer kann auch ziemlich klein sein.

    jup. afair nur 10 zeichen bei MS-DOS. und keiner hats gemerkt.


  • Mod

    Ja, ich denke auch, dass ein Puffer für Tastatureingaben eher max. 20 Zeichen haben sollte, denn es wirkt - siehe Beispiel mit Warteschleife oben - extrem komisch, wenn da nach dem Tippen noch fast 100 Zeichen aus der Queue auf dem Bildschirm eintrudeln. 😃



  • Erhard Henkes schrieb:

    ...extrem komisch, wenn da nach dem Tippen noch fast 100 Zeichen aus der Queue auf dem Bildschirm eintrudeln.

    vor allem brauchste dir keine gedanken darum zu machen, wie du den fall handlest, wenn die queue voll ist und neue daten eintrudeln. das problem kriegste erst bei datenquellen, wo nix verloren gehen darf.
    🙂


  • Mod

    Noch ein Nachtrag zum Thema C vs C++:
    Lowlevel Magazin ( http://lowlevel.brainsware.org/old/files/lowlevel_4.pdf ):
    ..



  • ^^objective-c bringts auch nicht so: http://kerneltrap.org/mailarchive/linux-kernel/2007/11/30/463283
    aber es gibt auch das: http://de.wikipedia.org/wiki/Singularity
    (wobei der low-level code aber in C geschrieben wurde).
    🙂


  • Mod

    ..


  • Mod

    ..



  • Erhard Henkes schrieb:

    Diese Funktion ist ebenfalls ein merkwürdiges Konstrukt:

    page_t* get_page(ULONG address, UCHAR make, page_directory_t* dir)
    {
        address /= PAGESIZE;                // address ==> index.
        ULONG table_index = address / 1024; // ==> page table containing this address
    
        if (dir->tables[table_index])       // table already assigned
        {
            return &dir->tables[table_index]->pages[address%1024];
        }
        else if(make)
        {
            ULONG phys;
            dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
            k_memset(dir->tables[table_index], 0, PAGESIZE);
            dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
            return &dir->tables[table_index]->pages[address%1024];
        }
        else
            return 0;
    }
    

    hier ist eigentlich nur das letzte 'else' überflüssig.
    🙂


  • Mod

    (ULONG)-1 sollte man hier besser 0xFFFFFFFF schreiben?

    Ich habe übrigens von James Molloy schriftlich die Freigabe, seinen - aus meiner Sicht nicht uninteressanten - Sourcecode als Basis für eigene Entwicklungen im Rahmen des Tutorials nutzen zu dürfen. Man muss ja nicht immer wieder das Rad neu erfinden, wie man so schön sagt.

    Gerade die Verwendung des Bitsets beim Paging ist effizient. ..


  • Mod

    mach ans ende der funktion return (ULONG)-1;

    Ich habe das (ULONG)-1 aussterben lassen:

    Sieht momentan - ohne Warnungen - so aus:
    ..

    hier ist eigentlich nur das letzte 'else' überflüssig.

    Das mag sein, macht die Sache aber nur noch schlimmer. 🙄



  • Erhard Henkes schrieb:

    mach ans ende der funktion return (ULONG)-1;

    Ich habe das (ULONG)-1 aussterben lassen:

    dann mach wenigstens eine #define aus 0xFFFFFFFF. vergisste mal ein F, dann kannste wieder schön lange fehler suchen.

    Erhard Henkes schrieb:

    hier ist eigentlich nur das letzte 'else' überflüssig.

    Das mag sein, macht die Sache aber nur noch schlimmer.

    wieso? einfach wech damit und return 0 ans ende. bleibt das gleiche.
    🙂


  • Mod

    Jeder hat seinen Stil. 🕶



  • Erhard Henkes schrieb:

    Jeder hat seinen Stil.

    ok, aber es soll doch ein tutorial sein. wenn du die funktionen ihrer lesbarkeit beraubst und eventuell dadurch fehler einbaust (z.b. i++ ist oft nicht das selbe wie ++i), dann machst du's dir und deinen lesern nur unnötig schwer.
    🙂


  • Mod

    An ein paar Klammern soll es wahrlich nicht scheitern:
    ..

    Mir gefällt das sprechende index u. offset aber besser als i und j.
    Das große NFRAMES finde ich auch besser, weil konstant:

    ULONG  NFRAMES = PHYSICAL_MEMORY / PAGESIZE;
    

    Ich verwende das Präinkrement bevorzugt vor dem Postinkrement. In der for-Schleife spielt es keine Rolle.
    Welches #define ... würdest Du denn für 0xFFFFFFFF verwenden? Da hat mich Dein Vorschlag sogar überzeugt, das könnte man noch austauschen, man nimmt wohl am besten das aus limits.h:
    #define ULONG_MAX 4294967295UL also ULONG_MAX



  • Erhard Henkes schrieb:

    An ein paar Klammern soll es wahrlich nicht scheitern:

    alle daumen hoch^^

    Erhard Henkes schrieb:

    Mir gefällt das sprechende index u. offset aber besser als i und j.

    das ist ok, aussagekräftige bezeichner sind immer gut, solange sie auch das richtige ausdrücken.

    Erhard Henkes schrieb:

    Ich verwende das Präinkrement bevorzugt vor dem Postinkrement.

    naja, weil's dir vielleicht besser gefällt, aber für eine änderung gibt's keinen sachlichen grund, erst recht nicht, wenn der code vorher schon gut funktionierte. ich behaupte mal, die meisten c-programmierer benutzen eher das post-increment. mir jedenfalls sticht ein pre-increment immer ins auge und ich denke mir 'warum macht das hier jemand so? das hat mehr zu bedeuten, als nur die variable hochzuzählen'.

    Erhard Henkes schrieb:

    Welches #define ... würdest Du denn für 0xFFFFFFFF verwenden? Da hat mich Dein Vorschlag sogar überzeugt, das könnte man noch austauschen.

    das 0xFFFFFFFF bedeutet hier doch 'ungültiger wert' oder sowas, dann könnteste es z.b. INVALID_VALUE o.ä. taufen.

    btw, und was selbstdefinierte typen angeht: ULONG sieht aus wie ein #define (alles gross geschrieben). nimm doch als typedef uint32_t. das wäre dann sogar richtig modern, C99-mässig
    🙂


  • Mod

    Ich finde dieses angehängte _t für Standardtypen irgendwie lästig.

    typedef unsigned int   UINT;
    typedef unsigned char  UCHAR;
    typedef unsigned short USHORT;
    typedef unsigned long  ULONG;
    typedef signed char    CHAR;
    

    findet man in os.h. Schön ist dies wirklich nicht, aber auf jeden Fall kürzer als unsigned xxx. Zumindest habe ich nicht BYTE, WORD und DWORD verwendet. 😃

    Die Code-Einfärbung kennt dies auch noch nicht:

    uint32_t zahl
    

    Da mir Didaktik wichtig ist, wie sieht dies die Allgemeinheit?


Anmelden zum Antworten