Eigenes OS?


  • Mod

    Yes, the k_malloc(...) of James Molloy (I have his written permission to use his source code as a base for own experiments in an OS tutorial, if I like, but I am not sure, if his code is really robust enough) is usable and is not the problem (Other people think, JM has put too much into paging.h/paging.c, because phys./virt. memory management should be separated clearly. This can be done easily.).

    OK, alignment is not important. I was not quite sure about it.

    Currently, I do not understand the difference in the result of EIP between cases 1) and 3). In 3) I just save the physical address at 0x01 or a variable phys. The reason must be in the way of saving details of the tasks. Hence, the clobbering can influence the deficient process. 🙄

    I think, I should go back to the test code where the task switch really works and analyze the effects by looking at all the details again. I just did and the page fault came, too. Thus, the failure has another reason. That's good. 🙂
    As soon as I have analyzed it, I will come back.

    @PHPnerd: Thanks for staying with me in times of confusion. 👍

    I use the following "stable version":
    ckernel.c (like main.c):

    UCHAR c=0;
    	while(TRUE)
    	{
    
    	  if( k_checkKQ_and_print_char() )
    	  {
    	    ++c;
    
    	    if(c>5)
    	    {
    	      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);
    
              task_switch(); settextcolor(getpid(),0);
    	    }
    	  }
    	}
    

    kjsdfhsdkjksdjfhksdjfhsdkjfhksdjfhksdjfhsdkjfhsdkjfhksdjfhkjsdfhksjdhfß
    T: 0000D80Fh H: 0000D80Fh WRITE: 66 Read: 66 *T: d 100 *H: d 100rnel_stack: 4010
    task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->ph
    ys: 00426000hk install
    placement_address after ram disk install: 40200000h
    ramdisk_start: 40081000h file_data_start: 0000A2C0h file_data_end: 0000B632h
    After set_kernel_stack ==> tss_entry.esp0: 40101800h

    > IRQ 127 <<<
    Hello, user world!
    Found file dev
    (directory)
    Found file f1
    contents: "PrettyOS: My filename is test1.txt!"
    Found file f2
    contents: "PrettyOS: My filename is test2.txt!"
    Found file f3
    contents: "PrettyOS: My filename is test3.txt!"
    placement_address after creating a new process: 40200000h phys: 0041CBE8h
    fork() returned: 00000002h and getpid() returned: 00000001h
    placement_address after creating a new process: 40200000h phys: 0041CC18h
    fork() returned: 00000003h and getpid() returned: 00000001h
    placement_address after creating a new process: 40200000h phys: 0041CC48h
    fork() returned: 00000004h and getpid() returned: 00000001h
    SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000018h, DS: 00000020h

    While entering keystrokes, the task is switched after every sixth keystroke.
    The logs of 'task_switch before asm:' with the original and 3 forked tasks are:

    task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h //PID 2

    task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00422000h //PID 3

    task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00426000h //PID 4

    task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00001000h //PID 1

    task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h //PID 2

    task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00422000h //PID 3

    task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00426000h //PID 4

    task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00001000h //PID 1 - the same as line 4

    ff.

    These are the data of the forked tasks:

    phys: 0041CBE8h
    fork() returned: 00000002h

    phys: 0041CC18h
    fork() returned: 00000003h

    phys: 0041CC48h
    fork() returned: 00000004h

    SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000018h, DS: 00000020h

    The task switch runs "unclobbered". Now it comes:

    If I clobber ebx and edx (see above), then I get a PF:

    task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h
    Page Fault (page not present) at 0040FCA0h - EIP: 0040FCA0h

    If I shift the task switch to timer handler, then I get an "Absturz":

    task_switch before asm: eip: 0000D303h esp: 0018FE74h ebp: 0018FE8Ch cur_dir->phys: 00001000h
    ...
    task_switch before asm: eip: 0000D303h esp: 0018FE74h ebp: 0018FE8Ch cur_dir->phys: 00001000h
    ...
    task_switch before asm: eip: 0000D303h esp: 0018FF70h ebp: 0018FF88h cur_dir->phys: 00001000h
    ...
    task_switch before asm: eip: 0000D303h esp: 0018FE74h ebp: 0018FE8Ch cur_dir->phys: 00001000h
    ...
    task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h
    ...
    placement_address after creating a new process: 40200000h phys: 0041CC18h
    fork() returned: 00000003h and getpid() returned: 00000002h
    placement_address after creating a new process: 40200000h phys: 0041CC48h
    fork() returned: 00000004h and getpid() returned: 00000002h
    SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h

    ==> Absturz (no exception, no reboot, just nothing besides blinking cursor)

    I think, this shows that JM's function task_switch() does not correctly work. Caring only for eip, esp, ebp seems to be not enough! Right?


  • Mod

    @PHPnerd: How do you switch tasks? Are you willing to show your new kmalloc?



  • I do not switch tasks yet. I will explain main for it later here 🙂

    And, I am using DogLea Algorithm with my own code.
    So:
    Headers and footers
    List containing free blocks, sorted by size

    Like the JamesM one, but than all my own code (like it more :P)

    Maybe look deeper in Intel Manuals of the source of other OSes to get idea's 😛

    // PHPnerd



  • With the multitasker:

    Try to save more registers, since you don't have a TSS.

    Save:
    EFLAGS <-- 🙂
    Segment registers: CS, DS, ES, FS, GS
    Possible save some general registers (can be done later)

    Maybe the EFLAGS will save the problem.
    Oh, and, did you do a end-of-interrupt before task switch when using switching in PIT? May be important.

    // PHPnerd


  • Mod

    Save: FLAGS/EFLAGS

    How can I do that? Is there a name for it in assembler? But I have read that you need not save them for task switch. 🙂

    I think the problem is with eip. I have logged it just before the asm code and directly after the task_switch():

    task_switch before asm: eip: 0000D54Fh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h PID: 2
    after task_switch: eip: 00008B11h esp: 0018FFE0h ebp: 0018FFF0h cur_dir->phys: 0041E000h PID: 2
    

    D54Fh vs. 8B11h ? But the task switch runs in this special case:

    ///TEST
        printformat("task_switch before asm: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",eip,esp,ebp,current_directory->physicalAddr, getpid());
        ///TEST
    
        asm volatile("       \
        cli;                 \
        mov %%ebx, %%esp;    \
        mov %%edx, %%ebp;    \
        mov %%eax, %%cr3;    \
        mov $0x12345, %%eax; \
        sti;                 \
        jmp *%%ecx;          "
                   : : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );
    

    ... changed to named registers.

    while(TRUE)
    	{
    
    	  if( k_checkKQ_and_print_char() )
    	  {
    	    ++c;
    
    	    if(c>5)
    	    {
    	      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);
    
              task_switch(); 
              ///TEST
              printformat("after task_switch: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",read_eip(),fetchESP(),fetchEBP(),current_directory->physicalAddr, getpid());
              ///TEST
              settextcolor(getpid(),0);
    	    }
    	  }
    	}
    


  • Does it work now?

    // PHP


  • Mod

    Only in the while loop at the above shown location. I think that the failure is at another place, perhaps concerning kernel_stack of the task. I come back to that.

    EDIT: One failure was in fork(): now new_task->kernel_stack instead of current_task->...

    I log the processes with its data, the first task looks strange:

    HEAP start: 40081000h end: 40100000h max: 4FFFF000h kernel mode: 0 read-only: 0
    hole 40081000h hole-size: 0007F000h after create_heap: placement_address: 0030C020h  allocated frames: 795
    
    VFS & RAM Disk install
    placement_address after ram disk install: 40200000h ramdisk_start: 40081000h file_data_start: 0000A200h file_data_end: 0000B572h
    
    tasking install
    move stack, ESP: 0018FFD0h After init first task, p_a: 40200000h After k_malloc kernel_stack, p_a: 40200000h k_stack: 40101000h 
    
    placement_address after creating a new process: 40200000h phys: 0041C814h
    fork(): 00000002h and getpid(): 00000001h
    placement_address after creating a new process: 40200000h phys: 0041C844h
    fork(): 00000003h and getpid(): 00000001h
    placement_address after creating a new process: 40200000h phys: 0041C874h
    fork(): 00000004h and getpid(): 00000001h
    t->id: 1, esp: 00000000h, eip: 00000000h k_stack: 40101000h, p_dir: 00000000h next: 40101814h
    t->id: 2, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 40105000h, p_dir: 40102000h next: 40101844h
    t->id: 3, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 40109000h, p_dir: 40106000h next: 40101874h
    t->id: 4, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 4010D000h, p_dir: 4010A000h next: 00000000h
    
    SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h
    

    after typing keys and taskswitching by that:

    kjdfghjkkhjkhkjkhkjhkkjh
    task_switch before asm: eip: 0000D216h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00001000h PID: 1
    after task_switch in ckernel.c: eip: 000089C7h esp: 0018FFE0h ebp: 0018FFF0h cur_dir->phys: 00001000h PID: 1
    
    

    Improved Sourcecode: http://www.henkessoft.de/OS_Dev/Downloads/40.zip
    I think it is not yet ready for the timer_handler, but I am on the right track now.



  • Good!~

    I almost finished my kmalloc. Working on Shrink now. Next is krealloc, but I may skip that one for now.

    I will continue ordering my OS, and then the MultiTasker.

    // PHP


  • Mod

    To my mind, the crucial point is that the source code stays transparent. 🙂

    There was a create_heap(...) inside of paging_install(). I have taken it out, because the heap is more complicated to visualize by printformat(...), and process' stacks were created in the heap! 😃 🙄

    Now there is a new exception, if you put the task_switch() to practice inside the time_handler (k_m_nonheap means "pushing" placement_address, no heap):

    k_m_nonheap k_m_nonheap k_m_nonheap k_m_nonheap k_m_nonheap
    p_a: 0040D000h allocated frames: 1053
    frames: 00400000h NFRAMES: 524288
    k_dir->phys: 00406000h
    p_a: 0040D000h allocated frames: 1053

    k_m_nonheap

    tasking install
    stack, ESP: 0018FFD0h k_m_nonheap Init first task, p_a: 00410020h cur_task: 00410004h k_m_nonheap After k_malloc k_stack, p_a: 00411800h k_stack: 00411000h

    k_m_nonheap k_m_nonheap placement_address after creating a new process: 00414020h phys: 00414004h
    k_m_nonheap fork(): 00000002h and getpid(): 00000001h
    k_m_nonheap k_m_nonheap placement_address after creating a new process: 00418020h phys: 00418004h
    k_m_nonheap fork(): 00000003h and getpid(): 00000001h
    t->id: 1, esp: 00000000h, eip: 00000000h k_stack: 00411000h, p_dir: 0040E000h next: 00414004h
    t->id: 2, esp: 0018FFD8h, eip: 0000D379h k_stack: 00415000h, p_dir: 00412000h next: 00418004h
    t->id: 3, esp: 0018FFD8h, eip: 0000D379h k_stack: 00419000h, p_dir: 00416000h next: 00000000h

    p_a: 00419800h

    SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h

    task_switch before asm: cur_task->p_dir: 00412000h task_switch before asm:
    eip: 0000D379h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00413000h PID: 2
    Invalid Opcode >>> Exception. System Halted! <<<

    Wie kann man den "Invalid Opcode" besser auswerten? z.B. Invalid Opcode ... at address ...? Ich habe mir z.B. r->eip angeschaut. Das passt einfach nicht zu dem in task_t. Verflixt! 😞

    Tippt man vor dem Timer Handler schnell noch ein paar task switches, dann findet man:

    klxdfgjkldfgjdfkgjkldfgjkldfgjkldfgjkldfjglkdfgjlkdfgjkldfjgkldfjglk
    task_switch before asm: cur_task->p_dir: 0040E000h task_switch before asm: eip: 0000D1BBh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0040F000h PID: 10h ebp: 0018FFF0h cur
    Invalid Opcode >>> Exception. System Halted! <<<

    This is the test code in ckernel.c (main.c):

    int main()
    {
    //...
    
        settextcolor(2,0); printformat("paging install\n"); settextcolor(15,0);
        paging_install();
    
        settextcolor(2,0); printformat("tasking install\n"); settextcolor(15,0);
        tasking_install(); settextcolor(15,0);
        int retValFork1 = fork(); int retValGetPid1 = getpid();
        printformat("fork(): %x and getpid(): %x\n", retValFork1, retValGetPid1);
        int retValFork2 = fork(); int retValGetPid2 = getpid();
        printformat("fork(): %x and getpid(): %x\n", retValFork2, retValGetPid2);
        int retValFork3 = fork(); int retValGetPid3 = getpid();
        printformat("fork(): %x and getpid(): %x\n", retValFork3, retValGetPid3);
    
        task_t* t = current_task;
        while(TRUE) {
            while(t->next) {
              printformat("t->id: %d, esp: %x, eip: %x k_stack: %x, p_dir: %x next: %x\n", t->id, t->esp, t->eip, t->kernel_stack, t->page_directory, t->next);
              t = t->next;
            }
            printformat("t->id: %d, esp: %x, eip: %x k_stack: %x, p_dir: %x next: %x\n", t->id, t->esp, t->eip, t->kernel_stack, t->page_directory, t->next);
            break;
        }
        printformat("p_a: %x \n", placement_address);
        printformat("SS: %x, ESP: %x, EBP: %x, CS: %x, DS: %x\n", fetchSS(),fetchESP(),fetchEBP(),fetchCS(),fetchDS());
        settextcolor(2,0);
        UCHAR c=0;
    	while(TRUE) {
    	  if( k_checkKQ_and_print_char() ) {
    	    ++c;
    	    if(c>5) {
    	      c=0;
    	      task_switch();
                  printformat("after task_switch in ckernel.c: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",read_eip(),fetchESP(),fetchEBP(),current_directory->physicalAddr, getpid());
                  settextcolor(getpid(),0);
    	    }
    	  }
    	}
    	return 0;
    }
    

    EDIT:
    I have printed now the infos from the struct reg by evaluating the exception in the IRQ/fault handler:

    placement_address: 00419800h
    SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h
    task_switch before asm: cur_task->p_dir: 00412000h eip: 0000D4D9h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00413000h PID: 2

    Invalid Opcode >>> Exception. System Halted! <<<
    err_code: 00000000h address(eip): 0000024Bh edi: 00000020h esi: 00000000h ebp: 00000008h esp: 0018FFE8h eax: 000000D7h ebx: 00000000h ecx: 00012345h edx: 0000D7F0h cs: 8 ds: 16 es: 16 fs: 16 gs 16 ss 2097144 int_no 6 eflags 00010202h useresp 00000000h

    These should be the data direct after the asm-code in task switch.
    address: 24Bh (eip) cannot be correct, if we enter with D4D9h.
    The ss 2097144 = 1FFFF8h looks "kaput". It should be 16 (10h). 😞
    eflags: 10000001000000010b = 10202h

    The whole task_management has to be looked thru.
    JM's code in this area is not robust, it was only for short demos.


  • Mod

    Ich habe jetzt mal pushf und popf eingebaut, um die flags zu sichern:

    asm volatile("       \
        cli;                 \
        pushf;               \
        mov %%ebx, %%esp;    \
        mov %%edx, %%ebp;    \
        mov %%eax, %%cr3;    \
        mov $0x12345, %%eax; \
        popf;                \
        sti;                 \
        jmp *%%ecx;          "
                   : : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );
    

    Ergebnis via task_switch mittels timer:

    p_a: 00419800h
    SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h
    task_switch before asm: cur_task->p_dir: 00412000h eip: 0000D519h esp: 0018FFD8
    h ebp: 0018FFF0h cur_dir->phys: 00413000h PID: 2 ss: 16
    err_code: 00000000h address(eip): 0000D40Bh
    edi: 0018FFF0h esi: 0018FFD8h ebp: 0018FFF0h esp: 0018FFC8h eax: 00012345h ebx:
    0018FFD8h ecx: 0000D519h edx: 0018FFF0h
    cs: 8 ds: 16 es: 16 fs: 16 gs 16 ss 55376
    int_no 1 eflags 00007FC6h useresp 00418000h
    Debug >>> Exception. System Halted! <<<

    Jetzt haben wir eine DEBUG Exception. 😃

    Übrigens: Wenn ich pushfd / popfd verwenden will, macht mein oldtimer gcc (verwendet wegen aout Format von NASM um den Asemblercode einzubinden) das nicht mit:

    c:/djgpp/tmp/cc5s5oYe.s: Assembler messages:
    c:/djgpp/tmp/cc5s5oYe.s:237: Error: no such instruction: pushfd' c:/djgpp/tmp/cc5s5oYe.s:237: Error: no such instruction:popfd'

    kann also nur die FLAGS nicht die EFLAGS sichern. 😕

    EDIT: Ich denke inzwischen, dass JM's Sourcecode im Bereich (multi)tasking für PrettyOS einfach unbrauchbar ist.

    Auf jeden Fall hat mir die Beschäftigung mit den Themen viel gebracht, bin nun auch oft genug gegen den Baum gefahren, um zu wissen, was etwas taugt und was einem bei Problemen nur noch den Rest gibt.

    Daher mache ich nun einen kompletten "roll-back" und setze am Ende des Tutorials an. !!!Schnitt!!! ⚠



  • Wird es nicht mehr weiter entwickelt oder was?????


  • Mod

    Roll-back starts now:

    Tutorial: http://www.henkessoft.de/OS_Dev/OS_Dev1.htm
    Source Code: ..

    Zunächst mal einige Fragen an euch zu den Tools (nasm/gcc/ld):

    1. Im Tutorial werden gcc 3.1 und ld 2.13 (im Rahmen von DJGPP, Download-Link von osdever.net empfohlen: http://www.osdever.net/downloads/compilers/DJGPP-Installer-nocpp.exe ) verwendet.
      Einer der Gründe besteht darin, dass wir damit das aout-Format (Linux a.out object file) linken konnten. abc.w konnte dieses Problem, soweit ich es verstanden habe, auch nicht lösen, sodass wir dabei blieben. Mit dem gcc 3.1 kommt man allerdings immer suspekt daher. Ein Fehler könnte ja am Uralt-Compiler liegen.

    Mögliche NASM output-Formate sind:
    bin, aout, aoutb, coff, elf32, elf, elf64, as86, obj ...

    Verwendet man für die NASM outputs COFF bzw. WIN32, dann gibt es folgende nette Meldung:
    kernel.asm: ... : error: COFF format does not support non-32-bit relocations
    Soweit ich das verstanden habe, hängt dies an unserem eleganten Übergang von 16 Bit nach 32 Bit. Hier erhält man von "Fachleuten" den Rat, GRUB einzusetzen und sich auf den C-Kernel zu konzentrieren. Das widerspricht aber dem Geist des bisherigen Tutorials, das die Dinge bottom-up zeigen will. Ich habe außer diesem aout-Format bisher kein Format gefunden, dass sowohl 16- als auch 32-Bit verarbeitet und von ld zum restlichen C-Code gebunden wird. Gibt es ein modernes Format, das dies kann?

    Ich bin nicht sicher, inweiweit dies ein echtes Problem oder nur Ansichtssache ist. GCC 3.1 stammt ja immerhin schon von May 15, 2002. Also so richtig uralt ist er nicht.

    Warum wurde z.B. pushfd / popfd im asm-Code nicht akzeptiert? Das kann doch nicht am gcc-Baudatum 2002 liegen, den 386er asm-Set gibt es seit den 80ern.

    1. zur AT&T-Syntax: %eax %%eax *%%eax
      wo muss man genau was verwenden?


  • Erhard Henkes schrieb:

    Auf jeden Fall hat mir die Beschäftigung mit den Themen viel gebracht, bin nun auch oft genug gegen den Baum gefahren, um zu wissen, was etwas taugt und was einem bei Problemen nur noch den Rest gibt.

    meiner meinung nach hast du zu viele themen gleichzeitig bearbeitet. das liegt wohl auch daran, dass es keine richtige trennung zwischen den komponenten des 'referenzsystems' von JM gibt (vermutlich ist er ein opfer der verfrickelten x86-technologie geworden, die einem instabile software-konstrukte aufzwingt). dabei kann man virtual memory, multitasking, heaps und exceptions ziemlich unabhängig voneinander betrachten. aber egal, nur nicht aufgeben...
    🙂


  • Mod

    Den Mut habe ich keinesfalls verloren, ganz im Gegenteil! Man kann ein solches Tutorial keinesfalls schreiben, wenn man schon 20 verschiedene OS entwickelt hat, weil man sich dann für garnix mehr entscheiden kann und alles nur noch theoretisch/abstrakt sieht, aber auch nicht aus dem Nichts. Inzwischen verstehe ich, warum JM nicht weiter macht. 😉

    dabei kann man virtual memory, multitasking, heaps und exceptions ziemlich unabhängig voneinander betrachten

    Ja, das stimmt. Es gibt daneben noch weitere Punkte, nämlich die Trennung des physikalischen und virtuellen MM, die Software-Interrupts, die Syscalls und die Ausführung von Programmen. Das VFS und die RAM-Disk gefallen mir gut von JM, wobei sein VFS noch nicht ausgefeilt ist, aber das kann man ja noch machen. Heap-Mechanismus funktioniert auch gut. Vielleicht liefert uns PHPnerd etwas Besseres, aber sein Ansatz klingt für mich gleich zu JM, aber ich bin kein Informatiker.


  • Mod

    Ich habe mit Teil 2 begonnen und die Themen FIFO circular Key Queue und "lean" key handler verarbeitet, um den Anschluss an das Tutorial zu bekommen.
    http://www.henkessoft.de/OS_Dev/OS_Dev2.htm (Tut)
    http://www.henkessoft.de/OS_Dev/Downloads/20090501_PrettyOS_101.zip

    Was mir wirklich Sorgen macht, ist, dass ich mit DJGPP arbeite, gilt als obsolet. leider haben wir 16-bit im Gepäck. Vielleicht kann man das auf 32-Bit abändern und auf COFF umsteigen.


  • Mod

    Wird es nicht mehr weiter entwickelt oder was?????

    Ganz im Gegenteil, jetzt geht es erst richtig los, allerdings geordnet, so robust wie möglich und transparent, damit eigenes Experimentieren gelingt. 🙂 Einfach dabei bleiben, oder noch besser, zusammen mit mir entwickeln. Ich werde nicht aufgeben. Das Thema OSDEV ist faszinierend. Ich werde ab jetzt aber jede einzelne Code-Zeile - egal ob fremd oder von mir selbst - auf die Goldwaage legen. Anders geht es nicht.

    Es gibt bezüglich Teil 2 folgende technische Fragestellungen:

    1. GRUB oder Tiny Bootloader?
    2. DJGPP oder neuere gcc-ld-binutils-Toolchain


  • Let's all take the Intel Manuals, close the jamesMolloy website, and start by ourself. We just use GRUB to load, so we take the GRUB specifications too.

    We read the GRUB specifications, and we find out how to make our starting OS multiboot able for GRUB. When done, we move to C, by just calling our C function.

    Read Intel manuals, on IDT, GDT, ISR and IRQ's (exceptions), work out some code.

    We already know howto use VGA in protected mode: writing to 0xb8000, write some nice code to make our life easier.

    Then, go on to intel manuals again, and go starting writing your PMM and VMM. (Volume 3A, Protected Mode Memory Management)

    Then, when all is working, do some research on internet about different algorithms of memory allocation (heap management). Write your own, without looking to others code. 🙂

    Debug debug debug all you got. Try to get your friends starting it and doing weird things.

    When done, Take Intel manuals and find the chapters about task management, but especially (when you want to use Software Multitasking) the chapter about the architecture itself. I think it is chapter 3 of Volume 1, not sure 😉

    Then go on writing some code to change the registers of the CPU. Just try to switch static tasks, then try make dynamic ones (so a task can start a new task).

    Go on to write code for device drivers and file systems, write some drivers, and
    support a nice filesystem (FAT32 for example). Then support executables, port newlib, compile the whole GCC packet. Run it on your OS, compile NASM. Write some simple nice text editor. Do not forget to make a command line interface for executing your commands.

    Now you can make your OS on your OS. And you can take a drink.

    When someone got so far, tip me, and i will tell you next steps (LOL, I will be back after some years and check the forum (just joking, will still be here)).

    Success you all! When you want some details (tips), ask for them.

    // PHPnerd


  • Mod

    Thank you for the guideline showing the path forward to OS excellence. 🙂



  • PHPnerd schrieb:

    Then, go on to intel manuals again...

    ...but don't rely on too much intel crap. only the very low level stuff (which must be coded in asm, anyway) should be hooked on x86. separate cpu specific code from the rest of the system, so you can...
    1. easily port your OS to another architecture
    2. run and debug parts of the OS inside a test bench (perhaps under windoze)
    🙂



  • Erhard Henkes schrieb:

    1. zur AT&T-Syntax: %eax %%eax *%%eax
      wo muss man genau was verwenden?

    Man muss unterscheiden zwischen Assembler-Syntax für den GNU Assembler und dem Assembler-Inline Formalismus für den gcc Compiler.

    Für den GNU Assembler gilt: Alle Register-Bezeichnungen, weil sie was besonderes sind, im Sinne, keine Variablen uns so was, bekommen ein % Zeichen. Man kann ruhig Variablen anlegen, die eax, ebx und sonst wie heissen, und auf diese Variablen zugreifen:

    .section .data
    eax: .long 0        # Variable eax
    ebx: .long 0        # Variable ebx
    ecx: .long 0, 0, 0  # Ein Array ecx[3]
    
    .section .text
    _Helper:
        movl %eax, eax      # Speichere Inhalt des CPU-Registers EAX (%eax) in der Variable eax (eax)
        movl %ebx, ebx      # Speichere Inhalt des CPU-Registers EBX (%ebx) in der Variable ebx (ebx)
        movl $eax, %eax     # Lade Addresse der Variable eax ($eax) ins CPU-Register EAX (%eax)
        movl $ecx, %ecx     # Lade Anfangsadresse des Arrays ecx ($ecx) ins CPU-Register ECX (%ecx)
        movl %eax, (%ecx)   # Speichere Inhalt des CPU-Registers EAX (%eax) im Array-Element ecx[0]
        movl %ebx, 4(%ecx)  # Speichere Inhalt des CPU-Registers EBX (%ebx) im Array-Element ecx[1]
        movl %ecx, 8(%ecx)  # Speichere Inhalt des CPU-Registers ECX (%ecx) im Array-Element ecx[2]
        ret
    

    Bei indirekten Sprüngen ist es so, dass ein Sternchen benützt werden muss/soll:

    _Sprung:
        jmpl *1000      # Effektive Adresse 1000
        jmpl *%eax      # Effektive Adresse im CPU-Register EAX (%eax)
        jmpl *4(%eax)   # Effektive Adresse im CPU-Register EAX (%eax) und Displacement = 4
        jmpl *(%eax, %ebx)  # Basis im CPU-Register EAX (%eax), Index im CPU-Register EBX (%ebx)
        jmpl *32(%eax, %ebx, 4) # Basis im CPU-Register EAX (%eax), Index im CPU-Register EBX, Skalierung = 4, Displacement = 32
        ret
    

    Vergisst man ein Sternchen zu setzen, kommt vom gas eine Warnung:

    ... Warning: indirect jmp without `*'

    Warum das so ist, weiss ich ehrlich gesagt nicht, habe im Manual dazu nichts gefunden und habe ehrlich gesagt, nicht intensiv danach gesucht.

    Bezüglich Assembler-Inline im C-Code kann ich leider nicht viel sagen. Ich weiss nur, dass man bei Registern zwei % Zeichen setzen muss. Ansonsten lässt sich, denke ich, obige Info auch so übernehmen. Und es gibt noch eine weitere Schar von Regeln für den Inline, die man kennen sollte...

    Ich hoffe, ich konnte bisschen Licht auf die AT&T Syntax werfen (die ja zu unrecht verteufelt wird)... 😉


Anmelden zum Antworten