Eigenes OS?


  • Mod

    Danke für den interessanten Einwurf. 🙂

    hihi, ich möchte nicht in deinen schuhen stecken.

    Das Problem ist, dass alles miteinander vernetzt ist, aber so ist es nun einmal.



  • Erhard Henkes schrieb:

    Das Problem ist, dass alles miteinander vernetzt ist, aber so ist es nun einmal.

    deswegen sollteste frühzeitig das ganze in überschaubare teilkomponenten zerlegen, KISS-prinzip, teile und herrsche und so.
    🙂



  • Erhard Henkes schrieb:

    hihi, ich möchte nicht in deinen schuhen stecken.

    Das Problem ist, dass alles miteinander vernetzt ist, aber so ist es nun einmal.

    hihi, ich möchte nicht in deinen schuhen stecken.


  • Mod

    deswegen sollteste frühzeitig das ganze in überschaubare teilkomponenten zerlegen

    Genau dies werde ich versuchen, soweit das möglich ist. Paging, Heap, Task Switching, User Mode vs Kernel Mode, Syscalls, VFS sind solche Einheiten, die allerdings zum einfachen Begreifen teilweise zu groß sind. Da versuche ich gerade, Unterelemente als elementare Module weiter heraus zu schneiden.

    Noch wichtiger ist die Visualisierung / Verständlichmachung dessen, was passiert, wenn man dies oder jenes ändert, weil viele Leute beim Verstehen und Begreifen eher praktisch an die Dinge heran gehen.

    ..

    Der Schwachpunkt von PrettyOS besteht momentan noch darin, dass noch kein Fileformat festgelegt wurde (jedoch kein Problem) und noch kein Mechanismus zum Übertragen von "Files" (Laden/Lesen Schreiben/Speichern), z.B. aus der RAM Disk in den Speicher und umgekehrt existiert. Sobald diese Mechanismen funktionieren, komme ich auf dieses Thema "proprietäre high-speed Datenschnittstelle zwischen OS und User Mode" zurück. Es geht nichts verloren. Wie sehen die entsprechenden Pendants bei Linux und Windows genau aus, damit ich das im Detail studieren kann?



  • Erhard Henkes schrieb:

    Wie sehen die entsprechenden Pendants bei Linux und Windows genau aus, damit ich das im Detail studieren kann?

    win haste ja schon gefunden. bei linux heißt die schlüsselfunktion mmap http://linux.die.net/man/3/mmap


  • Mod

    Danke! 🙂



  • Erhard Henkes schrieb:

    Wie sehen die entsprechenden Pendants bei Linux und Windows genau aus, damit ich das im Detail studieren kann?

    http://www.i.u-tokyo.ac.jp/edu/training/ss/lecture/new-documents/Lectures/
    unter: 10-LPC. auch der rest, z.b. memory management, dürfte dich auch interessieren.
    🙂


  • Mod

    @+fricky: Danke für den Link!
    Momentan interessiert mich dies hier am meisten, da ich davon bisher nur einen Bruchteil habe, und mir genau der Rest fehlt: 😉
    http://www.i.u-tokyo.ac.jp/edu/training/ss/lecture/new-documents/Lectures/02-VirtualMemory/VirtualMemory.pdf
    PrettyOS muss aber nicht wirklich performant sein, sondern vor allem verständlich, eben als Experimentier-Plattform geeignet. Ich bin mir noch nicht sicher, ob mir das gelingt, hängt davon ab, inwieweit mir geeignete Visualisierungs-Funktionen für die einzelnen Module und Exceptions gelingen.

    Gibt es eine Übersicht, wie man weitere Infos aus Registern erhält, um Exceptions möglichst vollständig zu analysieren? Dann könnte man diese Funktion, die bisher nur Page Faults genauer unter die Lupe nimmt, weiter ausbauen:
    ..
    r->err_code und das Register cr2 dürften wohl der Schlüssel dazu sein. Wenn man beim "Spielen" mit dem Code in ckernel.c auf eine Exception trifft, sollte man heraus finden können, was man eigentlich falsch gemacht hat. Das ist momentan noch nicht ausreichend gegeben. Das ist aus meiner Sicht noch das Hauptproblem.



  • English, my German is not very well.

    Try to create some code for installing fault handlers, so each fault handler does have its own function. Check if a custom handler is installed, and execute it. If not, write down a message on the screen and halt CPU (cli, hlt, for(;;);)
    Keeping them apart this way like, is very handy for dynamically installing and removing handlers. Also, when having a Virtual86Mode implemented, you will need #GP (general protection fault) very often, and write some big routines for it.

    for the Debug and Break exception you can write some nice simple handler. Just dump all registers given as argument in function call.

    The Page Fault handler:
    Receive the CR3 AND CR2. CR2 contains faulting address. CR3 the PHYSICAL address of the page directory. Then, split the faulting address in some parts.
    PageDirectoryIndex (cr2 >> 22, when using 4kb pages on a 32-bit system)
    PageTableIndex ((cr2 >> 12) & 0x3ff)
    PageOffset ((cr2 & 0xfff), not necessary for now)

    Then, when page was not present, check the PDE for present bit, then the existence of the PageTable (PDE->frame << 12 and then to virtual), then present of PTE, and then existence of the page mapped to the PTE. (PTE->frame != 0x0)

    Solve any of these things, but keep patience: be sure caller should be able to write or read something at the address in cr2.

    When having r/w (read/write) page fault and is present, kill the process. It is trying to access kernel space. Same way with u/s (user/supervisor).

    When looking at the Intel Manual, we see that there is NO ID bit in the error code of a #PF (page fault).
    Reserved, if problems with that, kill process. (or maybe just continuing is fine too)

    greetings, and success.

    // PHPnerd 😃


  • Mod

    @PHPnerd: thank you very much. 🙂



  • Keine Probleme. 😛

    I will look at this topic often to help here 🙂
    I am busy with kmalloc.

    The memory management part is the most boring, tricky and frustrating part of OS development.Don't quit 😛

    Also: be sure you always print out messages of exceptions, especially at the page fault exception. There shouldn't be ANY exceptions occur when programming kernel itself.

    // PHPnerd



  • PHPnerd schrieb:

    There shouldn't be ANY exceptions occur when programming kernel itself.

    even if the kernel is 100% bug free, third-party modules (device drivers and similar stuff running in kernel space) can crash the system. erhard should implement an exception handling mechanism, so that common errors (like wild pointers, divison by zero, etc.) are handled properly.
    🙂



  • Yeah, but kernel itself (main routine, setting up paging) should 😛

    Writing div by zero handler. I think that should be setting return value to zero.

    so
    int a = 5/0;
    a will be zero, instead of killing process.

    // PHPnerd



  • PHPnerd schrieb:

    so
    int a = 5/0;
    a will be zero, instead of killing process.

    no, that keeps the error. the error creeps forward and will cause weird behaviour of the whole thing. instead, exceptions should be 'handled' in a controlled manner (like this):

    ...
    begin_guarded_section();
    {
      ...
      int a = x/0;
      ...
    }
    if (get_exception_code() == DIV_BY_ZERO)  // enter exception handler 
    {
      // deal with division by 0
    }
    end_guarded_section();  // stop guarding
    ...   // process will be killed at this point, if another exceptions occur
    

    ^^all can be done using c-functions. there's no need for a modfied compiler (like that is the case with structured exception handling under m$-windoofs).
    🙂



  • So, no kernelmode div by zero handler?

    Erhard: do not forget to invalidate the TLB. use INVLPG (see Intel manuals) or read CR3, and write it to it again.

    // PHPnerd



  • PHPnerd schrieb:

    So, no kernelmode div by zero handler?

    of course, kernel must handle that, but must not terminate the application if an exception occurs inside guarded code. after that, the application should ask the kernel for exception code and (if there is one), retry the operation, notify the user, abort the program or something like that.
    🙂



  • All right, understand. But that is something for later on to me 😛

    // PHPnerd


  • Mod

    Yes, exception handling has to be fine-tuned in PrettyOS. Currently, there is only a message and a big stop sign. Page faults are already analyzed deeper.

    I worked on the VFS and the RAM disk, because it is very important to bring data, specialized kernel modules or user code into the memory of the OS. The way how it works now is as follows:

    1. produce a binary image from various files (with "make_initrd.exe", source code: "make_initrd.c"). I renamed the resulting image to "file_data.dat". This is the target for incbin in process.asm.

    2a) include it in process.asm with incbin, global addresses:

    ; data for ramdisk
    global _file_data_start
    global _file_data_end
    _file_data_start:
    incbin "file_data.dat"
    _file_data_end:
    

    2b) Linker transfers it to the memory at &file_data_start

    1. The source code line
    k_memcpy((void*)ramdisk_start, &file_data_start, (ULONG)&file_data_end - (ULONG)&file_data_start);
    

    in ckernel.c transfers the data with the files to the RAM disk (this is the way we exchange data with PrettyOS at the time being)

    1. The Virtual File System (VFS) with individual file headers helps to access the files in the RAM disk

    Enjoy it! 🙂

    PrettyOS: http://www.henkessoft.de/OS_Dev/Downloads/36.zip
    Screenshot: http://www.henkessoft.de/OS_Dev/Downloads/ramdisk_test.png

    Currently the framework for booting, loading asm kernel, switch to PM and C-kernel, interrupts, write/read key queue, set system timer frequency (I use 100 Hz), paging, heap, virtual file system, RAM disk, multitasking, syscalls now basically work. 🙂



  • Erhard Henkes schrieb:

    Hier ein prinzipielles Beispiel mit Erzeugung mehrerer Tasks und Taskswitch:...

    Aha, jetzt wird's interessanter und praxisbezogener...


  • Mod

    Aha, jetzt wird's interessanter und praxisbezogener...

    Die letzten beiden Wochen habe ich mich - zumindest grundlegend - um die komplexen Themen Memory-, Task- und File-Management (VFS, RAM Disk) sowie Syscalls gekümmert, um zu sehen, wie man dies am besten aufbauen und darstellen könnte. Manchmal sucht man auch nur "ewig" nach einem Fehler im Sourcecode. Hierbei behebt man dann zunächst noch alle möglichen anderen Baustellen, die man bei genauerem Hinsehen als nicht korrekt aufspürt. Bei mir liegen die "üblen" Fehler immer im Zeiger-Bereich. Kleines Beispiel:

    Diese Zeile hatte ich schnell "hingehauen":

    k_memcpy((void*)ramdisk_start, &file_data_start, &file_data_end - &file_data_start);
    

    Mit k_memshow(...) sah ich zufrieden, dass die "eingelinkten" Daten gefunden und sauber an den Anfang der RAM Disk kopiert wurden.
    Das Schlimme ist, dass durch die Pointer-Arithmetik zu wenige Daten kopiert wurden. Über die Blödsinnigkeit dieses Fehlers (es gibt nur wenige geniale Fehler) möchte ich hier nicht reden, so etwas passiert eben ab und zu, wenn man den cast auf die Schnelle vergisst. Dieses Wechselspiel zwischen Speicheradresse und Darstellung als unsigned long integer (ULONG) ist eine der Schwächen des Systems. Zwei kleine Casts nach ULONG, und schon funktionierte es perfekt:

    k_memcpy((void*)ramdisk_start, &file_data_start, (ULONG)&file_data_end - (ULONG)&file_data_start);
    

    Das Schlimme ist, dass man den Fehler an völlig anderer Stelle - nämlich den neu eingebauten Mechanismen - sucht. Auslöser ist, dass man große Speicherbereiche nicht auf einfache Weise wie bei einem Hex-Editor durchscrollen kann. Mir ist der Fehler erst aufgefallen, als ich mich mit k_memshow(...) auf die konkrete Stelle im Speicher gesetzt und dort nur Nullen gefunden habe. 😃
    Solche Erfahrungen sind in einem Tutorial wichtig und sollten auch dargestellt werden, damit andere an solche Trivialitäten denken, wenn Sie Fehler suchen. Denn das "Aufgeben" kommt oft daher, dass man Fehler nicht findet, keine geeigneten Vorbilder hat und/oder in einem Forum (http://forum.osdev.org/ ist ein Musterbeispiel) arrogant behandelt wird.

    Momentan schreibe ich an dem Tutorial noch nicht weiter, weil die grundlegenden Mechanismen zwar funktionieren, ich aber mit der Visualisierung noch nicht zufrieden bin.

    Erste zaghafte Beispiele für Visualisierung sind:

    void k_memshow(void* start, size_t count)
    {
        const UCHAR* end = (const UCHAR*)(start+count);
        for(; count != 0; count--) printformat("%x ",*(end-count));
    }
    

    und die Paging-Analyse-Funktionen

    ULONG show_physical_address(ULONG virtual_address)
    {
        page_t* page = get_page(virtual_address, 0, kernel_directory);
        return( (page->frame_addr)*PAGESIZE + (virtual_address&0xFFF) );
    }
    
    void analyze_physical_addresses()
    {
       int i,j,k, k_old;
        for(i=0;i<(PHYSICAL_MEMORY/0x18000+1);++i)
        {
            for(j=i*0x18000; j<i*0x18000+0x18000; j+=0x1000)
            {
                if(show_physical_address(j)==0)
                {
                    settextcolor(4,0);
                    k_old=k; k=1;
                }
                else
                {
                    if(show_physical_address(j)-j)
                    {
                        settextcolor(3,0);
                        k_old=k; k=2;
                    }
                    else
                    {
                        settextcolor(2,0);
                        k_old=k; k=3;
                    }
                }
                if(k!=k_old)
                    printformat("%x %x\n", j, show_physical_address(j));
            }
        }
    }
    

    Im Tasking-Bereich ist mir bisher nur die Darstellung der PID als Farbe beim "Tippen" (Schreiben/Lesen KeyQueue) eingefallen.
    Vor dem Heap-Gebäude stehe ich noch etwas zögerlich bezüglich Darstellung der "blocks and holes". Man hat im Textmode mit 80*25 mit wenigen brauchbaren Farben auch nicht allzu viele Möglichkeiten.

    Didaktische Ideen sind daher immer willkommen. 🙂


Anmelden zum Antworten