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

ehenkes

  • Gast
Gespeichert
« Antwort #60 am: 22. May 2009, 00:29 »
Zitat
0x0000839b - Da musst du die größte Adresse suchen, die kleiner ist als diese (oder gleich).
kernel.map:
Zitat
0x000083a0                _test1
0x0000836e                _test
0x00008330                _surprise

Das wäre dann also test?

ehenkes

  • Gast
Gespeichert
« Antwort #61 am: 22. May 2009, 00:43 »
@Porkchicken: Vielleicht kannst Du mir taktisch weiter helfen. Ich möchte echten User Mode (Ring 3) umsetzen. Das klappt bisher nicht. Ich habe es versucht, indem ich mittels create_task andere Funktionen als syscall_Funktion aufrufe, aber da beißen sich bisher zwei Stränge (syscall und create_task), die beide mit interrupts und iret arbeiten. Bei einer Verschachtelung hakt es dann (siehe oben). Rufe ich einen Syscall mit while(TRUE)-Schleife auf, dann bleibt er dabei hängen. kein Task-Switch mehr.

Eine prinzipielle Frage:
Ich habe Funktionen in create_task mit Deiner Hilfe wie folgt zum Laufen gebracht:
void moo()
{
  while(TRUE)
  {
      settextcolor(2,0);
      printformat("MOO %d", getpid()); // <-- cow
      settextcolor(15,0);
  }
}
Aber ich möchte nun auch das machen:
void moo()
{
      settextcolor(2,0);
      printformat("MOO %d", getpid()); // <-- cow
      settextcolor(15,0);
}
Als erstes passiert das:
Zitat
11111111111111111111111111111111111111111111111MOO 2
Page Fault (page not present) at 123890ABh - EIP: 123890ABh

err_code: 00000000h address(eip): 123890ABh
edi: 00000000h esi: 00000000h ebp: 00000000h eax: 0000000Fh ebx: 00000000h ecx: 000B8000h edx: 0000000Fh cs: 00000008h ds: 00000010h es: 00000010h fs: 00000010h gs 00000010h ss 123890ABh
int_no 14 eflags 00010206h useresp 40204FF4h
Das hat noch nichts mit User Mode zu schaffen, sondern immer noch Multitasking. Das Problem ist wohl das ret von moo(), das offensichtlich das Tasking stört.

Taljeth meint, ich solle mit einem Syscall zurück springen. Ein syscall ist bei mir der Aufruf einer Kernel-Fkt. aus Ring 3. Dieser syscall_... müsste doch das ret von moo() "aufhalten", indem er in eine Schleife (Ersatz für die while-Schleife) geht, bis der Dispatcher/Scheduler zuschlägt. Später noch informieren, dass zur Umschaltung bereit. Sehe ich das richtig?

Was macht ret?
Near Return: holt EIP vom Stack und springt dorthin (aber was ist das in diesem Fall? Was kommt nach einem einmaligen moo()in create_task? Irgendwie fehlt der Landeflughafen, bisher werden die Tasks im freien Flug geswitcht.  :-D ), CS unverändert.

Hier ist mein Stand: http://www.henkessoft.de/OS_Dev/Downloads/36y_user.zip

Dieses Experimentierfeld möchte ich nur nutzen, um den user mode zu testen.
Ich hänge leider
1) wegen eines Fehlers im User Mode (?)
2) zwischen syscall und create_task
übel fest.
Es wäre nett, wenn mir jemand einen Schubs in die richtige Richtung gegen könnte. 





« Letzte Änderung: 22. May 2009, 10:11 von ehenkes »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #62 am: 22. May 2009, 11:14 »
Das wäre dann also test?
Wenn du beachtet hast, dass die Liste nicht sortiert ist, ja.

Rufe ich einen Syscall mit while(TRUE)-Schleife auf, dann bleibt er dabei hängen. kein Task-Switch mehr.
Das ist nicht unerwartet: Im Kernel sind Interrupts deaktiviert -> kein präemptiver Task-Switch möglich. Lösung: Keine Endlosschleifen im Kernel. Du musst da auch nicht warten. Eine wartende Funktion sollte selbst den Task-Switch (Stack-Wechsel beim Verlassen des syscalls) initiieren können.

Zitat
Taljeth meint, ich solle mit einem Syscall zurück springen. Ein syscall ist bei mir der Aufruf einer Kernel-Fkt. aus Ring 3. Dieser syscall_... müsste doch das ret von moo() "aufhalten", indem er in eine Schleife (Ersatz für die while-Schleife) geht, bis der Dispatcher/Scheduler zuschlägt. Später noch informieren, dass zur Umschaltung bereit. Sehe ich das richtig?
Nein, der syscall kann den Task-Wechsel direkt vornehmen, und den esp-Wert vom neuen Task zurückgeben. Dann wird nach dem Syscall direkt zum nächsten Task gesprungen. Dazu braucht der Stub vom Syscall Handler die selbe Struktur wie der von den IRQs.

Der Syscall, der deinen Task beendet, sollte diesen Task aus der Liste der laufenden Tasks austragen, und zum nächsten Task in der Liste zurückkehren.

Zitat
Was macht ret?
Near Return: holt EIP vom Stack und springt dorthin (aber was ist das in diesem Fall? Was kommt nach einem einmaligen moo()in create_task?
Mit ret solltest du beim Taskwechsel nichts am Hut haben. Es sollte einfach kein ret ausgeführt werden, dass Probleme machen könnte.
Dieser Text wird unter jedem Beitrag angezeigt.

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #63 am: 22. May 2009, 11:24 »
So, ich versuche mich jetzt auch mal daran, das zu erklären. Ich bin zwar nicht PorkChicken, aber vielleicht hilfts ja trotzdem. ;-)

Also gehen wir das Ganze mal Schritt für Schritt durch, ausgegangen vom folgenden einfachen Usermode-Programm:
int main() {
    puts("Hallo Welt!");
    return 0;
}

Nun wie schon von taljeth erwähnt ist die main()-Funktion nicht der direkte Einsprungspunkt in den Task. Dafür hast du in der libc eine Funktion _start:
void start() {
    int result;
    // Hier würde man normalerweise noch sowas machen wie Parameter vom Kernel holen und parsen, aber das lassen wir der Einfachheit halber mal weg.

    result = main();
    syscall_exit(result);
}

Dabei ist es wichtig, dass die Funktion syscall_exit() nie zurückkehrt von einem Aufruf. Es handelt sich dabei ja, wie der Name sagt, um einen Syscall, der als Interrupt umgesetzt wird.

Wenn nun der Kernel diesen Syscall erhält, entfernt er den aktuellen Task aus dem Scheduler, und zestört (Speicher des Tasks und interne Strukturen werden freigegeben) ihn. Danach muss er logischerweise einen neuen Task schedulen, da der bisherige nicht mehr existiert.

In tyndur geht das so, dass der Interrupt-Handler eh immer den nächsten zu benutzenden Stackpointer zurueckgibt, und auch cr3 für den neuen Task lädt, wenn er gewechselt hat. Damit muss der Syscall-Handler im Wesentlichen nur current_task neu setzen und der Interrupthandler übernimmt dann den Rest.

So, ich hoffe, dass ich dich damit nicht noch mehr verwirrt habe.

Edit: Bäh, der PorkChicken war schneller. Aber ich lasse das jetzt trotzdem mal stehen. ;-)

ehenkes

  • Gast
Gespeichert
« Antwort #64 am: 22. May 2009, 11:49 »
Zitat
Danke an euch beide! Der Stub vom Syscall Handler u. Exceptions braucht also die gleiche Struktur wie der von den IRQs.
Ich denke, dies ist der erste notwendige Schritt, ist mir inzwischen auch klar geworden, dass diese Unsymmetrie (Exception und SW-Interrupt über fault_handler und IRQ0...IRQ15 über irq_handler noch dazu mit unterschiedlichem stub - habe ich von Bran's Tutorial geerbt) Probleme macht, denn, wenn ich es richtig sehe, soll sowohl ein syscall als auch exceptions und die IRQ0...15 einen task_switch durchführen können. 

EDIT: Ich habe die beiden stubs und irq_handler (da läuft IRQ0 rein) und fault_handler (da läuft der syscall rein) angeglichen. irq_tail und fault_tail sind nun exakt gleich. create_task setzt den eip des neuen tasks auf irq_tail. syscall_... schaltet nun jeweils einen task weiter. Eine Runde 1->6->1->4 hat auch geklappt. Hier bricht es mit PF ab. Interessant.

« Letzte Änderung: 22. May 2009, 13:06 von ehenkes »

ehenkes

  • Gast
Gespeichert
« Antwort #65 am: 22. May 2009, 15:16 »
Ich habe mich jetzt mal vorgetastet an die kritische Stelle, an der es beim zweiten Durchgang schief geht:

0x00008294  _irq_tail   (IRQ0...15)
0x000081f2  _fault_tail (exceptions u. sw-interrupt 7fh für syscalls



(0) [0x000082a6]  iretd      <== wenn ich es richtig sehe, zweite Hälfte vom Software-Interrupt  (fault_handler)             

 | STACK 0x4020d7f0 [0x0000d4fc]
 | STACK 0x4020d7f4 [0x00000008]
 | STACK 0x4020d7f8 [0x00000202]
 | STACK 0x4020d7fc [0x00000000]
 | STACK 0x4020d800 [0x123890ab]
 | STACK 0x4020d804 [0x4020cff4]
 | STACK 0x4020d808 [0x123890ab]
 | STACK 0x4020d80c [0x00000001]
 | STACK 0x4020d810 [0x000007f8]

 (0) [0x0000d4fc]  pop ebp                   
 (0) [0x0000d4fd]  ret

 | STACK 0x4020d800 [0x123890ab]
 | STACK 0x4020d804 [0x4020cff4]
 | STACK 0x4020d808 [0x123890ab]
 | STACK 0x4020d80c [0x00000001]
 | STACK 0x4020d810 [0x000007f8]

(0).[41476341]  ???  (physical address not available)

1-2-3-5-1-2-3!5  (task 4 und 6 nicht aktiviert)

Dies ist die Stelle zwischen 3 und 5, an der es - beim zweiten Durchgang - schief geht.

void f3()
{
  while(TRUE)
  {
      settextcolor(4,0);
      printformat("%d", getpid());
      settextcolor(15,0);
  }
}

void test5()
{
}

    task_t* task2 = create_task (f2,0);           
    task_t* task3 = create_task (f3,0);           
    task_t* task5 = create_task (syscall_test5,0);


Das d4fc muss doch falsch sein!

0x0000d4f2   _syscall_test5  (kernel.map)

objdump -D syscall.o > syscall.txt

00000012 <_syscall_test5>:
  12: 55                    push   %ebp
  13: 89 e5                mov    %esp,%ebp
  15: b8 01 00 00 00        mov    $0x1,%eax
  1a: cd 7f                int    $0x7f
  1c: 5d                    pop    %ebp
  1d: c3                    ret   

Dieses int $0x7f ist mein syscall-Software-Interrupt.

Dieser dürfte doch aber keinesfalls dorthin zurück, oder sehe ich das falsch?

Vielleicht läuft in fault_handler etwas schief und der return-Value kommt nicht an? (Habe es separat mit einem nop() davor getestet, kommt an und kehrt im geordneten Fall zu _fault_tail zurück):
ULONG fault_handler(ULONG esp)
{
    ULONG retVal;
    struct regs* r = (struct regs*)esp;

    if(!pODA->ts_flag)
        retVal = esp;
    else
        retVal = task_switch1(esp); //new task's esp

    if (r->int_no < 32) //exception
    {
        settextcolor(4,0);

        if (r->int_no == 6 || r->int_no == 1) //Invalid Opcode
        {...}

        if (r->int_no == 14) //Page Fault
        {...}

        printformat("\n");
        printformat("%s >>> Exception. System Halted! <<<", exception_messages[r->int_no]);
        for (;;);
    }

    if (r->int_no == 127) //sw-interrupt syscall
    {
        syscall_handler(r);
    }
    return retVal;
}

Dieser syscall_handler leitet ja nach syscall_puts weiter, wenn ich das richtig sehe.  :?

So sieht dieser aus:
void syscall_handler(struct regs* r)
{
    // Firstly, check if the requested syscall number is valid. The syscall number is found in EAX.
    if( r->eax >= num_syscalls )
        return;

    void* addr = syscalls[r->eax]; // Get the required syscall location.

    // We don't know how many parameters the function wants, so we just push them all onto the stack in the correct order.
    // The function will use all the parameters it wants, and we can pop them all back off afterwards.
    int ret;
    asm volatile (" \
      push %1; \
      push %2; \
      push %3; \
      push %4; \
      push %5; \
      call *%6; \
      pop %%ebx; \
      pop %%ebx; \
      pop %%ebx; \
      pop %%ebx; \
      pop %%ebx; \
      " : "=a" (ret) : "r" (r->edi), "r" (r->esi), "r" (r->edx), "r" (r->ecx), "r" (r->ebx), "r" (addr));
    r->eax = ret;
}
Hier der objdump von _syscall_handler zur Sicherheit wegen inline-Assembler:
00000032 <_syscall_handler>:
  32: 55                    push   %ebp
  33: 89 e5                mov    %esp,%ebp
  35: 57                    push   %edi
  36: 56                    push   %esi
  37: 53                    push   %ebx
  38: 83 ec 1c              sub    $0x1c,%esp
  3b: 8b 55 08              mov    0x8(%ebp),%edx
  3e: 8b 42 28              mov    0x28(%edx),%eax
  41: 3b 05 90 00 00 00    cmp    0x90,%eax
  47: 73 31                jae    7a <_syscall_handler+0x48>
  49: 8b 04 85 94 00 00 00 mov    0x94(,%eax,4),%eax
  50: 89 45 f0              mov    %eax,0xfffffff0(%ebp)
  53: 8b 4a 10              mov    0x10(%edx),%ecx
  56: 8b 5a 14              mov    0x14(%edx),%ebx
  59: 8b 72 20              mov    0x20(%edx),%esi
  5c: 8b 7a 24              mov    0x24(%edx),%edi
  5f: 8b 42 1c              mov    0x1c(%edx),%eax
  62: 8b 55 f0              mov    0xfffffff0(%ebp),%edx
  65: 51                    push   %ecx
  66: 53                    push   %ebx
  67: 56                    push   %esi
  68: 57                    push   %edi
  69: 50                    push   %eax
  6a: ff d2                call   *%edx
  6c: 5b                    pop    %ebx

Ich denke, die Analyse ist ausreichend. Ich bin mir nur noch nicht sicher, wo der entscheidende Fehler liegt, denn beim ersten Durchgang läuft es ja durch.

Zitat
...
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222233333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111111111111111111111111
11111111111111122222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222222222222222222222222222222222
22333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
333333333333333333333333333333333333333333333333333333333333333333333Page Fault
(page not present) at 123890ABh - EIP: 123890ABh

Page Fault >>> Exception. System Halted! <<<
1 - 2 - 3 - [5] - 1 - 2 - 3 ! [5]
(5 zeigt nichts an)

Hier ist der gesamte Code: http://www.henkessoft.de/OS_Dev/Downloads/20090522_36z.zip
« Letzte Änderung: 22. May 2009, 16:13 von ehenkes »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #66 am: 22. May 2009, 16:31 »
Das d4fc muss doch falsch sein!

0x0000d4f2   _syscall_test5  (kernel.map)

objdump -D syscall.o > syscall.txt
Das ist die falsche Datei. Du musst den Kernel disassemblieren nicht die Objektdateien, wenn du Kerneladressen überprüfen willst.
Zitat
Dieser syscall_handler leitet ja nach syscall_puts weiter, wenn ich das richtig sehe.  :?
Nein.
ULONG num_syscalls  = 3;
static void* syscalls[3] =
{
    &puts, <---------- 0
    &test5, <----------- 1
    &test6 <-------------- 2
};
Dieser Text wird unter jedem Beitrag angezeigt.

ehenkes

  • Gast
Gespeichert
« Antwort #67 am: 22. May 2009, 16:47 »
Da ich den fault_handler als "Übeltäter" im Visier habe:
ULONG fault_handler(ULONG esp)
{
    ULONG retVal;
   
    //...

    if (r->int_no == 127) //sw-interrupt syscall
    {
        syscall_handler(r);
    }
    nop();///TEST for debugger
    return retVal;
}

Mit einem Breakpoint auf nop(), dann muss ich jeweils noch einige Steps gehen bis zum übernächsten ret (eins gehört ja zu nop() ).

Nach dem ersten "Hello, user world": 0x000081f2  _fault_tail

beim zweiten Halt (in task 1 durch IRQ0): 0x000097a4  (0x00009784  _irq_handler, nächste kleinere Adresse in kernel.map)

beim dritten Halt (am Ende von task 2 durch IRQ0): 0x000097a4

beim vierten Halt (am Ende von task 3 durch IRQ0): 0x000097a4

(task4 wurde nicht aktiviert)

beim fünften Halt (Einstieg in task 5 durch syscall_test5): 0x000093ca (0x000093a6   _fault_handler, nächste kleinere Adresse in kernel.map)

beim sechsten Halt (am Ende von task 5 durch ??): 0x000081f2 _fault_tail in kernel.map

Umstieg 5 -> 1 klappt!

beim siebten Halt (am Ende von task 1 durch IRQ0): 0x000097a4

beim achten Halt (am Ende von task 2 durch IRQ0): 0x000097a4

beim neunten Halt (am Ende von task 3 durch IRQ0): 0x000097a4

beim zehnten Halt (Einstieg in task 5 durch syscall_test5): 0x000093ca (0x000093a6   _fault_handler, nächste kleinere Adresse in kernel.map)

-> Pagefault

Hier die beiden Stacks beim Einstieg in task 5 zum Vergleich:

 | STACK 0x4020d774 [0x000093ca]
 | STACK 0x4020d778 [0x4020d7bc]
 | STACK 0x4020d77c [0x00000000]
 | STACK 0x4020d780 [0x00000000]


 | STACK 0x4020d77c [0x000093ca]
 | STACK 0x4020d780 [0x4020d7c4]
 | STACK 0x4020d784 [0x00009563]
 | STACK 0x4020d788 [0x00000000]

Aus irgendwelchen düsteren Gründen ist der Stack nun zwei ULONG-Einheiten länger.
« Letzte Änderung: 22. May 2009, 17:16 von ehenkes »

ehenkes

  • Gast
Gespeichert
« Antwort #68 am: 22. May 2009, 17:03 »
Zitat
Du musst den Kernel disassemblieren nicht die Objektdateien, wenn du Kerneladressen überprüfen willst.
Die Adressen finde ich doch in kernel.map. Ich wollte nur in der Objektdatei nachschauen, wie wirklich in Assembler übersetzt wurde.

ld -T kernel.ld kernel.o isr.o ckernel.o video.o flush.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o process.o ordered_array.o paging.o kheap.o descriptor_tables.o task.o fs.o initrd.o syscall.o  -o ckernel.bin -Map kernel.map

objdump -D ckernel.bin >ckernel.txt
File format not recognized

ndisasmw ckernel.bin >ckernel.txt (erfolgreich)
Darin finde ich aber nichts, alles am Stück.  :-D

Wie lautet der Hero Debugger Befehl?  :-)

Mit meiner Methode muss ich eben noch relativ selbst abzählen.

Ich sehe vor allem den entscheidenden Fehler noch nicht. Lasst ihr mich einfach hängen oder seht ihr ihn auch nicht? Macht hier bloß keinen auf Oberlehrer.  :-(
« Letzte Änderung: 22. May 2009, 17:18 von ehenkes »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #69 am: 22. May 2009, 17:23 »
Ach die eigentlich entscheidene Frage, wurde immer noch nicht beantwortet ... Also ss und esp werden auf dem Stack vor cs gepusht. Steht aber auch in den Intel Manuals Kapitel 5.12 oder so. Die sind bei deinem Stand dringend angebrachte Lektüre.

Ah, ja der Oberlehrer-Kommentar trifft zu. Ich bin hier der.
« Letzte Änderung: 22. May 2009, 17:25 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

ehenkes

  • Gast
Gespeichert
« Antwort #70 am: 22. May 2009, 17:40 »
Zitat
Also ss und esp werden auf dem Stack vor cs gepusht.
Ja, das liegt sogar ausgedruckt neben mir unter einem Stapel von Büchern:
eflags, cs, eip, error code ohne Privileg-Wechsel
ss, esp, eflags, cs, eip, error code mit Privileg-Wechsel
(Wer denkt sich nur so einen Mist aus?)

Den User Mode habe ich ja noch gar nicht aktiviert? Da knallt es sowieso immer, ist alles noch kernel privileg, also ring 0.

Wenn Du mir jetzt noch einen Tipp geben könntest, wo das zusätzlich rein muss. Nein, stopp! bei create_task(...), wenn der Parameter privileg  3 ist, richtig?


« Letzte Änderung: 22. May 2009, 17:46 von ehenkes »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #71 am: 22. May 2009, 17:50 »
Ja.
Dieser Text wird unter jedem Beitrag angezeigt.

ehenkes

  • Gast
Gespeichert
« Antwort #72 am: 22. May 2009, 17:52 »
Nur zur Sicherheit, weil das immer so lax gehandhabt wird:
sind das esp3 und ss3 oder esp0 und ss0?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #73 am: 22. May 2009, 17:59 »
In ss muss ein User-Mode-Selektor und esp muss auf den User-Mode-Stack zeigen. Also esp3 und ss3. (Auch wenn glaub ich die Namen ungünstig sind, weil es nicht die Werte in der TSS sind.)
Dieser Text wird unter jedem Beitrag angezeigt.

ehenkes

  • Gast
Gespeichert
« Antwort #74 am: 22. May 2009, 18:08 »
Bisher habe ich nur einen Kernel-Stack. Kann ich den hier auch für den User-Stack nehmen oder brauche ich auch noch einen zusätzlichen user-stack? SS wäre dann 0x23 (gate 4 mit Privileg 3). 

Aber der Fehler, den ich gefunden habe, lag nicht daran, denn die Tasks waren alle Privileg 0.

typedef struct task
{
    int id;                           // Process ID.
    ULONG esp, ebp;                   // Stack and base pointers.
    ULONG eip;                        // Instruction pointer.
    ULONG ss;
    page_directory_t* page_directory; // Page directory.
    ULONG kernel_stack;               // Kernel stack location.
    struct task* next;                // The next task in a linked list.
} task_t;


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;

    *(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0

    ULONG code_segment=0x08, data_segment=0x10;
    if(privilege == 0) code_segment = 0x08;
    if(privilege == 3)
    {
        *(--kernel_stack) = new_task->ss = 0x23; // ss
        *(--kernel_stack) = new_task->esp = new_task->kernel_stack; // esp
        code_segment = 0x1B; // 0x18|0x3=0x1B
    }

    *(--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;

    // data segment registers
    if(privilege == 0) data_segment = 0x10;
    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 task_t
    new_task->ebp = 0xd00fc0de; // test value
    new_task->kernel_stack = (ULONG)kernel_stack;
    new_task->esp          = (ULONG)kernel_stack;
    new_task->eip = (ULONG)irq_tail;
    new_task->ss  = data_segment;

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

    sti();
    return new_task;
}
So o.k.? oder noch ein extra user-stack mit kmalloc?

Damit:

Versuch 1:
task_t* task5 = create_task (syscall_test5,0);  =>
Beim zweiten Durchgang:
Zitat
333333333333333333333333333333333333333333333333333333333333333333333
Page Fault (page not present) at 123890ABh - EIP: 123890ABh
Warum sollte sich auch etwas ändern?
versuch2:
task_t* task5 = create_task (syscall_test5,3); =>
beim ersten Durchgang, also sofort bei task 5:
Zitat
33333333333333333333333333333333333333333333333333333333333333333333333333333333
33333
General Protection Fault >>> Exception. System Halted! <<<

Intel Kap. 5.12 war also nicht der Grund. Dennoch guter Hinweis bezüglich user mode. Hatte ich erst mal weg gelassen, weil ich das mit dem Parameter privilege noch nicht eingebaut hatte.

Brauche ich hier schon einen user stack oder ist der hier identisch mit dem kernel-stack? Muss das in TSS->esp3 TSS->ss3 eingetragen werden?

« Letzte Änderung: 22. May 2009, 18:42 von ehenkes »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #75 am: 22. May 2009, 19:17 »
Also ss und esp werden auf dem Stack vor cs gepusht.
Stimmt natürlich nicht. Vor eflags werden die auf den Stack gelegt.
Dieser Text wird unter jedem Beitrag angezeigt.

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #76 am: 22. May 2009, 19:20 »
Brauche ich hier schon einen user stack oder ist der hier identisch mit dem kernel-stack? Muss das in TSS->esp3 TSS->ss3 eingetragen werden?
Sobald du Ring3-Prozesse hast, brauchst du einen zusätzlichen Stack. Dieser sollte dann auch mit User-Privilegien gemappt sein, sonst fliegen die Pagefaults frischfrölich. ;-)

ehenkes

  • Gast
Gespeichert
« Antwort #77 am: 22. May 2009, 19:28 »
Zitat
eflags, cs, eip, error code ohne Privileg-Wechsel
ss, esp, eflags, cs, eip, error code mit Privileg-Wechsel
Ich schreibe es richtig, und mache es dann doch so wie du es sagst.  :-D

ehenkes

  • Gast
Gespeichert
« Antwort #78 am: 22. May 2009, 19:46 »
Jetzt habe ich noch mehr Probleme, weil das totale Chaos zwischen esp0, esp3, esp(?) und kernel_stack ausgebrochen ist. Liegt an meiner beschissenen Task-Struktur, die ich von JM übernommen habe. Nur noch Reset.

Ich unterscheide jetzt zwischen:
esp0 = kernel_stack
esp3 = user_stack
ss0   = kernel_stack_segment
ss3   = user_stack_segment

Fangen wir mal am task_switch an, denn da haut es jetzt raus:
Was ist das für ein esp der da herum gereicht wird? esp0 oder esp3?

Wie sieht eure Struktur aus?
« Letzte Änderung: 22. May 2009, 19:52 von ehenkes »

ehenkes

  • Gast
Gespeichert
« Antwort #79 am: 22. May 2009, 19:50 »
Zitat
Sobald du Ring3-Prozesse hast, brauchst du einen zusätzlichen Stack. Dieser sollte dann auch mit User-Privilegien gemappt sein
Danke für den Hinweis.

Das Problem ist, dass die grundlegenden Fehler (im MultiTasking und im UserMode) bei mir noch nicht gefunden sind. Das zeigt mir, dass meine Gesamtstruktur noch nicht tauglich ist. Aber was soll's, der Weg ist das Ziel.  :-P

Ich lese jetzt Intel Manual, vielleicht hilft das weiter:

Zitat
When the processor performs a call to the exception- or interrupt-handler procedure:

•If the handler procedure is going to be executed at a numerically lower privilege level, a stack switch occurs.

When the stack switch occurs:

a.The segment selector and stack pointer for the stack to be used by the handler are obtained from the TSS for the currently executing task. On this new stack, the processor pushes the stack segment selector and stack pointer of the interrupted procedure.

b.The processor then saves the current state of the EFLAGS, CS, and EIP registers on the new stack (see Figures 5-4).

c.If an exception causes an error code to be saved, it is pushed on the new stack after the EIP value.

•If the handler procedure is going to be executed at the same privilege level as the interrupted procedure:

a.The processor saves the current state of the EFLAGS, CS, and EIP registers on the current stack (see Figures 5-4).

b.If an exception causes an error code to be saved, it is pushed on the current stack after the EIP value.

Also beim Wechsel von 3 nach 0 benötigt man einen Kernel-Stack. Das lege ich in create_task an und baue es passend auf. Für einen unterbrochenen Prozess in Ring 3 legt man wohl ss3 und esp3 ("stack segment selector and stack pointer of the interrupted procedure") vor eflags auf den Kernel-Stack.   Woher kommen ss3 und esp3? "... are obtained from the TSS for the currently executing task". Hmmm?
« Letzte Änderung: 22. May 2009, 20:52 von ehenkes »

 

Einloggen