Autor Thema: Programm laden und ausführen  (Gelesen 26285 mal)

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #80 am: 22. May 2009, 21:14 »
Aus dem TSS werden nur ss0 und esp0 ausgelesen.

Das auf den Stack Legen von ss(3) und esp(3) machst du für ein iret, nicht für den Aufruf des Interrupts.
Dieser Text wird unter jedem Beitrag angezeigt.

ehenkes

  • Gast
Gespeichert
« Antwort #81 am: 22. May 2009, 21:29 »
Ich bin zunächst zu einer funktionierenden Version mit Endlos-while-Schleife beim Aufruf der Funktion zurück gekehrt, um den user mode mit der neuen Erkenntnis mit ss und esp vor eflags zu testen, und es geht! Ich bin sogar etwas verblüfft.

void test5()
{
  while(TRUE)
  {
      syscall_puts("5");
      //puts("5");
  }
}

    task_t* task2 = create_task (f2,0);           // function moo in kernel
    task_t* task3 = create_task (f3,0);           // function baa in kernel
    task_t* task4 = create_task2(f4,0,4,2);       // function ... in kernel
    task_t* task5 = create_task (test5,3);    // <=== user mode !!!
    task_t* task6 = create_task2(test6,0,ramdisk_start+(ULONG)&prog_start-(ULONG)&file_data_start,0);

task_t* create_task(void* entry, UCHAR privilege)
{
    cli();
    page_directory_t* directory = clone_directory(current_directory);
    task_t* new_task            = (task_t*)k_malloc(sizeof(task_t),0,0);

    new_task->id  = next_pid++;
    new_task->page_directory = directory;
    new_task->kernel_stack   = k_malloc(KERNEL_STACK_SIZE,1,0)+KERNEL_STACK_SIZE;
    new_task->next = 0;

    task_t* tmp_task = (task_t*)ready_queue;
    while (tmp_task->next)
        tmp_task = tmp_task->next;
    tmp_task->next = new_task; // ... and extend it

    ULONG* kernel_stack = (ULONG*) new_task->kernel_stack;

    ULONG code_segment=0x08, data_segment=0x10;

    if(privilege == 3)
    {
        //Intel 3A Chapter 5.12
        *(--kernel_stack) = new_task->ss = 0x23;    // ss
        *(--kernel_stack) = new_task->kernel_stack; // esp0
        code_segment = 0x1B; // 0x18|0x3=0x1B
    }

    *(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0
    *(--kernel_stack) = code_segment; // cs
    *(--kernel_stack) = (ULONG)entry; // eip
    *(--kernel_stack) = 0; // error code

    *(--kernel_stack) = 0; // interrupt nummer

    // general purpose registers w/o esp
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;

    if(privilege == 3) data_segment = 0x23; // 0x20|0x3=0x23

    *(--kernel_stack) = data_segment;
    *(--kernel_stack) = data_segment;
    *(--kernel_stack) = data_segment;
    *(--kernel_stack) = data_segment;

    //setup TSS
    tss_entry.ss0   = 0x10;
    tss_entry.esp0  = new_task->kernel_stack;
    tss_entry.ss    = data_segment;

    //setup task_t
    new_task->ebp = 0xd00fc0de; // test value
    new_task->esp = (ULONG)kernel_stack;
    new_task->eip = (ULONG)irq_tail;
    new_task->ss  = data_segment;

    sti();
    return new_task;
}

Das läuft, aber etwas seltsam. Die 5 wird immer nur einmal ausgegeben.
Offenbar passiert da etwas seltsames, muss ich im Debugger genau sehen.  Denn dieses einmalige Ausführen einer Funktion möchte ich ja gerade erreichen.

EDIT: Habe mir das im Debugger angeschaut. Als Rücksprungadresse des syscalls im Interrupt ist test6 enthalten, weil ich ja beim syscall z.Z. automatisch einen direkten Taskwechsel habe.  :-)


Streiche ich das while, dann klappt es mindestens ein Mal, dann kommt aber wieder PF mit dem magic code, wie bereits vorne mit dem Debugger intensiv untersucht, aber leider noch nicht gelöst.
Zitat
44444444444444444444444444444444444444444444444444444444444444444444444444444444
45  666666666666666666666666666666666666666666666666666666666666666666666666666666

Dass es sich wirklich um User Mode handelt, sieht man, wenn man nicht syscall_puts, sondern puts verwendet:
Zitat
44444444444444444444444444444444444444444444444444444444444444444444444444444444
4444444444444444444
Page Fault ( read-only - write operation user-mode) at 000B8C06h - EIP: 00008986h

Was mich verblüfft, ist, dass ich test5(...) im Kernel aufrufen kann. ich hatte extra syscall_test5 produziert.  Aber offensichtlich erfolgt die Umschaltung auf Ring 3 etwas später in create_task, so dass man test5 als Einsprung-Adresse verwenden kann.

Endlich user mode!  :-)
Code: http://www.henkessoft.de/OS_Dev/Downloads/20090522_43_user_mode.zip


Das Umschalten des Tasks durch syscall kann man natürlich leicht unterbinden, was ich auch inzwischen gemacht habe:
ULONG fault_handler(ULONG esp)
{
    ULONG retVal;
    struct regs* r = (struct regs*)esp;

    if(!pODA->ts_flag)
        retVal = esp;
    else
    {
        if(r->int_no == 127) //syscall
            retVal = esp;
        else
            retVal = task_switch1(esp); //new task's esp
    }
   
    //...
   
    if (r->int_no == 127) //sw-interrupt syscall
    {
        syscall_handler(r);
    }
    return retVal;
}
Zitat
4444444444444444444444444444444444444444444444444444444444444444444444444444444
5555555555555555555555555555555555555555555555555555555555555555555555555555555
555555555555555555555555555555555555555555555555
66666666666666666666666666666666666666666666666666666666666666666666666666666666
« Letzte Änderung: 22. May 2009, 23:21 von ehenkes »

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #82 am: 05. June 2009, 13:03 »
So.
Ich habe soeben das erste mal ein ELF-Programm ausgeführt und mein OS ist nicht abgestürzt. *g*
 
Allerdings habe ich noch ein kleines Problem.
Und zwar muss ich ja bei ELF-Dateien die ladbaren Abschnitte (.text und .data (momentan)) an die gegebene virtuelle Adresse laden, was momentan 0xa0000000 ist.
Dazu muss ich ja die Anzahl der benötigten Pages ermitteln und irgendwie stehe ich hier grad aufm Schlauch. Folgender Code wird momentan genutzt, da der andere nicht geht:
u32int_t num_needed_pages = ((program_header->p_memsz + (PAGE_SIZE - program_header->p_memsz)) / PAGE_SIZE);Allerdings kann ich dies nur benutzen, wenn die Größe kleiner als eine Page ist. Mein Ansatz, der nicht so will, wie ich will, sieht so aus:
u32int_t num_needed_pages = ((program_header->p_memsz + (program_header->p_memsz % PAGE_SIZE)) / PAGE_SIZE);Das Ergebnis was dann letzten endes raus kommt ist 0, warum auch immer...
 
Was ist hier bloß falsch, ich sehe es einfach nicht...
 
Gruß Christian
 
Anmerkung:
program_header->p_memsz beinhaltet 0x1b. Führe ich nur "program_header->p_memsz % PAGE_SIZE" aus und gebe das Ergebnis aus, bekomme ich 0x1b, was ja nicht korrekt ist.

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #83 am: 05. June 2009, 13:16 »
Anmerkung:
program_header->p_memsz beinhaltet 0x1b. Führe ich nur "program_header->p_memsz % PAGE_SIZE" aus und gebe das Ergebnis aus, bekomme ich 0x1b, was ja nicht korrekt ist.

Warum ist das falsch? Ich nehme mal an, PAGE_SIZE ist grösser als 0x1b, dann stimmt das doch genau?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #84 am: 05. June 2009, 13:44 »
wenn X % PAGE_SIZE == 0
dann
    Gerundet := X                                             (* X ist bereits Vielfaches von PAGE_SIZE *)
sonst
    Gerundet := X + (PAGE_SIZE - X % PAGE_SIZE)               (* Den fehlenden Rest addieren*)

Anzahl Seiten := Gerundet / PAGE_SIZE;

Oder wenn du das ohne Verzweigung machen willst:
Gerundet := (X + PAGE_SIZE - 1) and not (PAGE_SIZE - 1)       (* PAGE_SIZE muss eine Potenz von 2 sein *)
Anzahl Seiten := Gerundet / PAGE_SIZE;
Die Addition von PAGE_SIZE - 1 sorgt dafür, dass wir genau dann in der nächsten Seite landen, wenn wir runden müssen, und die bitweise "and not"-Operation, löscht die unteren 12 Bits. Das kannst du zum besseren Verständnis mal mit ein paar Werten in der Nähe von PAGE_SIZE durchspielen, wie z.B. 4095, 4096, 4097.
Dieser Text wird unter jedem Beitrag angezeigt.

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #85 am: 05. June 2009, 14:01 »
Verdammt...
ich wusste doch, dass ich irgendwo einen Denkfehler habe. Jetzt funktioniert alles, vielen Dank.

ehenkes

  • Gast
Gespeichert
« Antwort #86 am: 07. June 2009, 13:14 »
Kann ich das mit dem Laden der elf-Datei bei dir nachlesen? Link?

ChristianF

  • Beiträge: 296
    • Profil anzeigen
    • DeutschOS - Betriebssystem Projekt
Gespeichert
« Antwort #87 am: 08. June 2009, 10:10 »
Kann ich das mit dem Laden der elf-Datei bei dir nachlesen? Link?
Mmmmhhh...
Verwendet habe ich die Seite mit Informationen zum ELF-Format von der Lowlevel-Wiki: http://lowlevel.brainsware.org/wiki/index.php/ELF.
Dann hat mir noch der folgende Thread geholfen: http://lowlevel.brainsware.org/forum/index.php?topic=1017.msg11966#msg11966, zu dem aus einem anderen Thread verlinkt wurde...
Geladen werden die "Programme" von GRUB als Module.
Als letztes, was auch noch geholfen hat, da ich auch erst auf dem Schlauch gestanden habe, war der Code aus dem Tyndur Repository: http://git.tyndur.org/?p=tyndur.git;a=blob;f=src/lib/bin_loader/elf32.c.
 
Ich hoffe mal, das war, was du von mir hören wolltest.  :roll:
Wenn du in meinem Code lesen möchtest, müsste ich erst einmal den Admin des Servers fragen (auf dem das Repository liegt), da der Zugriff nur mit einem Benutzername und Passwort möglich ist. Oder ich poste ihn bei bedarf einfach hier...

ehenkes

  • Gast
Gespeichert
« Antwort #88 am: 09. June 2009, 00:07 »
Danke fuer die Links, komme leider erst naechste Woche zum Testen.

 

Einloggen