Autor Thema: Software Multitasking  (Gelesen 43571 mal)

ehenkes

  • Gast
Gespeichert
« Antwort #20 am: 27. April 2009, 01:47 »
Nun bekomme ich nur noch Page Faults. Offenbar erhält der EIP unter gewissen Umständen einen falschen Wert.

Erster Task Switch nach 20 sec (eingestellt im Time Handler):
Page Fault (page not present) at 0040FC20h - EIP: 0040FC20h

Sehr viele Task switches pro Sekunde:
Page Fault (page not present) at 0F000123h - EIP: 0F000123h

Aber immerhin. Offenbar hat die Clobber List den GPF gegen PF getauscht.  :-)

Funktion read_eip() ist in Assembler codiert (process.asm):

global _read_eip
_read_eip:
    pop eax               ; Get the return address
    jmp eax               ; Return. Can't use RET because return
                          ; address popped off the stack.
Vielleicht liegt hier der Hund begraben.

Ich habe diese gegen
global _read_eip
_read_eip:
    pop eax
    push eax
    ret
ausgetauscht. Sieht irgendwie besser aus, hilft aber nicht.  :-P
« Letzte Änderung: 27. April 2009, 19:06 von ehenkes »

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #21 am: 27. April 2009, 21:53 »
Zitat
can't find a register in class `GENERAL_REGS' while reloading `asm'
Ich verwende gcc.exe (Version 3.1) und ld.exe (Version 2.13) wegen Linkens des aout-Formats von NASM.
Kann sein, daß er esi und edi schon benutzt, um deine Variablen zwischenzuspeichern. Durch das "g" ist das alles etwas unbestimmt, nichts genaues weiß man nicht. Du kannst jetzt entweder versuchen, deinen Kernel hinterher zu disassemblieren und dir mal genau anzuschauen, ob der Zustand komplett und korrekt gespeichert wird. Oder du wirfst dieses Modell über den Haufen und machst den Switch im Assembler-Stub wie ich dir seit einigen Posts vorschlage. ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

ehenkes

  • Gast
Gespeichert
« Antwort #22 am: 28. April 2009, 19:32 »
Ich bin didaktisch interessiert, daher muss ich erst verstehen, was überhaupt falsch läuft. Clobbering ebx und edx, das leider noch zum Page Fault führt, gibt im objdump einen Hinweis, warum man nicht auch edi und esi clobbern kann:
35f:    fa                       cli   
 360:    89 f1                    mov    %esi,%ecx
 362:    89 fc                    mov    %edi,%esp
 364:    89 cd                    mov    %ecx,%ebp
 366:    0f 22 d8                 mov    %eax,%cr3
 369:    b8 45 23 01 00           mov    $0x12345,%eax
 36e:    fb                       sti   
 36f:    ff e1                    jmp    *%ecx

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #23 am: 28. April 2009, 20:39 »
Erster Task Switch nach 20 sec (eingestellt im Time Handler):
Page Fault (page not present) at 0040FC20h - EIP: 0040FC20h
Sollte denn diese Adresse gemappt sein?
Dieser Text wird unter jedem Beitrag angezeigt.

ehenkes

  • Gast
Gespeichert
« Antwort #24 am: 29. April 2009, 06:09 »
Nicht mehr genau dieses Programm:
002E0000h  11111111111111111111111111111111
00300000h  11111111111111111111111111111111
00320000h  11111111111111111111111111111111
00340000h  11111111111111111111111111111111
00360000h  11111111111111111111111111111111
00380000h  11111111111111111111111111111111
003A0000h  11111111111111111111111111111111
003C0000h  11111111111111111111111111111111
003E0000h  11111111111111111111111111111111
00400000h  11111111111111111111111111111111
00420000h  11111111100000000000000000000000
00440000h  00000000000000000000000000000000
00460000h  00000000000000000000000000000000
00480000h  00000000000000000000000000000000
004A0000h  00000000000000000000000000000000
004C0000h  00000000000000000000000000000000
004E0000h  00000000000000000000000000000000
Ich denke ja.  :?

Im Timer Handler komme ich noch nicht klar damit. Um zu verstehen, was wirklich wichtig ist, habe ich task_switch() an eine Stelle in einer while-Schleife im Hauptprogramm verlagert, in der es "stabil" nach jedem sechsten Tastenanschlag umschaltet (ich benutze den PID als Farbgeber).

Ohne Clobbern geht das. Sobald ich aber ebx und edx clobbere, gibt es einen PF:
Zitat
task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h
Page Fault (page not present) at 0040FCA0h - EIP: 0040FCA0h

ehenkes

  • Gast
Gespeichert
« Antwort #25 am: 29. April 2009, 06:17 »
clobbering ebx and edx ==> Page Fault:
      asm volatile("         \
      cli;                 \
      mov %0, %%ecx;       \
      mov %1, %%esp;       \
      mov %2, %%ebp;       \
      mov %3, %%cr3;       \
      mov $0x12345, %%eax; \
      sti;                 \
      jmp %%ecx;           "
      : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr)
      : "ebx","edx" );
   

objdump task.o -D > task.txt
35f:    fa                       cli   
 360:    89 f1                    mov    %esi,%ecx
 362:    89 fc                    mov    %edi,%esp
 364:    89 cd                    mov    %ecx,%ebp
 366:    0f 22 d8                 mov    %eax,%cr3
 369:    b8 45 23 01 00           mov    $0x12345,%eax
 36e:    fb                       sti   
 36f:    ff e1                    jmp    *%ecx
Man sieht hier, warum man edi und esi nicht clobbern kann.

Leere clobber list:   
351: fa cli
352: 89 d9 mov %ebx,%ecx
354: 89 f4 mov %esi,%esp
356: 89 fd mov %edi,%ebp
358: 0f 22 d8 mov %eax,%cr3
35b: b8 45 23 01 00 mov $0x12345,%eax
360: fb sti
361: ff e1 jmp *%ecx

clobbert man ebx:
35f:    fa              cli   
 360:    89 f1                  mov    %esi,%ecx
 362:    89 fc                  mov    %edi,%esp
 364:    89 d5                 mov    %edx,%ebp
 366:    0f 22 d8             mov    %eax,%cr3
 369:    b8 45 23 01 00  mov    $0x12345,%eax
 36e:    fb                       sti   
 36f:    ff e1                    jmp    *%ecx

clobbering edx:

 351:    fa                       cli   
 352:    89 d9                 mov    %ebx,%ecx
 354:    89 f4                  mov    %esi,%esp
 356:    89 fd                  mov    %edi,%ebp
 358:    0f 22 d8             mov    %eax,%cr3
 35b:    b8 45 23 01 00  mov    $0x12345,%eax
 360:    fb                       sti   
 361:    ff e1                    jmp    *%ecx

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #26 am: 29. April 2009, 11:53 »
35f:    fa                       cli   
 360:    89 f1                    mov    %esi,%ecx
 362:    89 fc                    mov    %edi,%esp
 364:    89 cd                    mov    %ecx,%ebp
 366:    0f 22 d8                 mov    %eax,%cr3
 369:    b8 45 23 01 00           mov    $0x12345,%eax
 36e:    fb                       sti   
 36f:    ff e1                    jmp    *%ecx
Hier ist das Register %ecx doppelt belegt. Am Anfang ist da als Eingabe der Basepointer drin. Dann wird %ecx mit %esi (dem Page Directory) überschrieben. Zwei Zeilen später wird %ecx nach %ebp kopiert. %ebp enthält jetzt also das Page Directory, und nicht den Stack Pointer. Du solltest auf benannte Register umsteigen:
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) );
Ist natürlich jetzt die Frage, ob das was bringt, oder ob dein ursprünglicher Code nicht genau das gleiche tut.

Außerdem gehören Register natürlich nicht auf die Clobber-List, wenn du sie (im Assembler Code) gar nicht benutzt. Wenn GCC die Register benutzt, weiß er schon selbst, was er tut. (Naja gut bei deinem alten GCC weiß man das nicht^^) Also ist nur eine leere Clobber-List korrekt.
Dieser Text wird unter jedem Beitrag angezeigt.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #27 am: 29. April 2009, 19:14 »
Außerdem gehören Register natürlich nicht auf die Clobber-List, wenn du sie (im Assembler Code) gar nicht benutzt. Wenn GCC die Register benutzt, weiß er schon selbst, was er tut. (Naja gut bei deinem alten GCC weiß man das nicht^^) Also ist nur eine leere Clobber-List korrekt.
Er benutzt die Register aber implizit. gcc weiß nicht, daß hier ein Taskwechsel stattfindet und könnte noch Zeug aus dem alten Task in den Registern stehen haben. Wenn man es unbedingt in C machen will, muß man also dafür sorgen, daß gcc alle Register auf den Stack packt und die Register das asm() nicht überleben. Dazu kann man die Clobber-Liste nehmen.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

ehenkes

  • Gast
Gespeichert
« Antwort #28 am: 01. May 2009, 08:30 »
Das Problem liegt leider auch noch an anderer Stelle. SS ist nicht korrekt. Momentan schlagen alle Schwächen gleichzeitig zu.  JM's Code ist im TaskSwitch Bereich nicht besonders brauchbar. Das wird mir immer klarer.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #29 am: 01. May 2009, 09:41 »
Wieso sollte der Taskswitch-Code ss ändern müssen? Er ist doch vorher und nachher im Kernelcode?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

ehenkes

  • Gast
Gespeichert
« Antwort #30 am: 01. May 2009, 13:14 »
Ja, völlig richtig. Das Problem liegt tiefer, nämlich im Interrupt asm und C Code. JM's Code ist da nur in Ansätzen - sprich als erste Demo - hilfreich, aber in der Praxis versagt und verwirrt er konkret, wie bei mir geschehen.  Daher mache ich bezüglich des Task Switch nun einen kompletten Roll-back.

Mal noch zwei konkrete Fragen zu diesem Thema:
1) Sollte man auch die Flags/EFlags sichern? Ist das überhaupt notwendig?
2) Im GCC 3.1 geht in asm(...) nur pushf/popf, pushfd/popfd wird nicht erkannt (das könnte man natürlich nach NASM auslagern und zurück linken). Liegt das an dem Alter dieser GCC-Version (2002, ich verwende diese wegen aout, weil coff keinen gemischten 16/32-bit-code akzeptiert)? Die 386 Instruktionen sind doch schon uralt dagegen.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #31 am: 01. May 2009, 13:24 »
1) Sollte man auch die Flags/EFlags sichern? Ist das überhaupt notwendig?
Ja, die werden aber automatisch bei einem Interrupt aus den Stack gelegt.

Zitat
2) Im GCC 3.1 geht in asm(...) nur pushf/popf, pushfd/popfd wird nicht erkannt (das könnte man natürlich nach NASM auslagern und zurück linken). Liegt das an dem Alter dieser GCC-Version (2002, ich verwende diese wegen aout, weil coff keinen gemischten 16/32-bit-code akzeptiert)? Die 386 Instruktionen sind doch schon uralt dagegen.
Warum brauchst du 16bit Instruktionen überhaupt? :-o
Abgesehen davon ist das offensichtlich keine dauerhaft Lösung...
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

ehenkes

  • Gast
Gespeichert
« Antwort #32 am: 03. May 2009, 11:48 »
Zitat
Warum brauchst du 16bit Instruktionen überhaupt?

http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId412221
Dort finden sich [Bits 16] und [Bits 32] in einer Übersetzungseinheit (Übergang von RM nach PM). Vielleicht kann man das so verändern, so dass man COFF verwenden kann?


Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #33 am: 03. May 2009, 11:57 »
Ich weiß nicht, warum das in vielen Tutorials immer so kompliziert gemacht wird, und 16 und 32 Bit Code vermischt wird ... Man kann doch einfach den Kernel komplett in 32 Bit halten (und im Bootloader natürlich weiterhin nur 16 Bit benutzen). Am Ende des Bootloader muss man den Sprung in den Protected Mode dann mit dem Sprung in den Kernel kombinieren.
Dieser Text wird unter jedem Beitrag angezeigt.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #34 am: 03. May 2009, 11:59 »
Im Binärformat kann man auf jeden Fall den Code vermischen. Aber ob dir das reicht weiß ich nicht. Müsste man halt eventuell noch ein Feld am Anfang unterbringen, in dem die Adresse vom Entry-Point steht oder so.

Ansonsten hat Jidder natürlich Recht, aber das hab ich ja oben auch mehr oder weniger gesagt...
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

ehenkes

  • Gast
Gespeichert
« Antwort #35 am: 03. May 2009, 12:11 »
In diesem Bild sieht man die Zusammenhänge:
http://www.henkessoft.de/OS_Dev/Bilder/make_process.PNG

Der Übergang von RM nach PM erfolgt in kernel.asm (16/32 bit).
Damit das Linken klappt, erzeuge ich aout-Format, was problemlos von der Kombination gcc 3.1 / ld 2.13 (in DJGPP) geschluckt wird.

Naja, vielleicht sollte mir das einfach egal sein. In anderen Tutorials habe ich bisher nur kompliziertere Wege gesehen als im oben genannten Tut.

Um GRUB führt auf Dauer sowieso kein Weg vorbei, werde ich in Teil 3 gezwungermaßen wohl angehen müssen. MS Windows User mögen dieses Teil allerdings überhaupt nicht, weil sie GRUB nicht haben. Eine selbst entwickelte Alternative fehlt. Unter Vista gibt es doch auch einen Bootloader? (verwende selbst noch Win XP)
« Letzte Änderung: 03. May 2009, 12:14 von ehenkes »

ehenkes

  • Gast
Gespeichert
« Antwort #36 am: 03. May 2009, 12:18 »
In diesem Bild sieht man die Zusammenhänge:
http://www.henkessoft.de/OS_Dev/Bilder/make_process.PNG

Der Übergang von RM nach PM erfolgt in kernel.asm (16/32 bit).
Damit das Linken klappt, erzeuge ich aout-Format, was problemlos von der Kombination gcc 3.1 / ld 2.13 (in DJGPP) geschluckt wird.

Naja, vielleicht sollte mir das einfach egal sein. In anderen Tutorials habe ich bisher nur kompliziertere Wege gesehen als im oben genannten Tut.

Ein Sprung aus dem Binär-Format nach C-Funktionen war nicht erlaubt. Daher konnte ich kernel.asm nicht als bin verwenden. ich musste auf o, dann war da aber das 16/32 bit Problem beim Linken, was ich via aout (es lebe hoch) lösen konnte.  :-)

Um GRUB führt auf Dauer sowieso kein Weg vorbei, werde ich in Teil 3 gezwungermaßen wohl angehen müssen. MS Windows User mögen dieses Teil allerdings überhaupt nicht, weil sie GRUB nicht haben. Eine selbst entwickelte Alternative fehlt. Unter Vista gibt es doch auch einen Bootloader? (verwende selbst noch Win XP)

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #37 am: 03. May 2009, 12:45 »
Zitat
Ein Sprung aus dem Binär-Format nach C-Funktionen war nicht erlaubt. Daher konnte ich kernel.asm nicht als bin verwenden.
Jo das ist klar, ich dachte auch eher an das Ausgabeformat .bin für den ges. gelinkten Kernel, was du aber offensichtlich schon verwendest.

Zitat
ich musste auf o, dann war da aber das 16/32 bit Problem beim Linken, was ich via aout (es lebe hoch) lösen konnte.  :-)
Wie bereits gesagt, 16bit Code mit 32Bit C-Code mischen ist nicht optimal. Dafür habe ich auch keine gescheite Lösung gesehen/gefunden.

Zitat
Unter Vista gibt es doch auch einen Bootloader? (verwende selbst noch Win XP)
Kommt gut, wenn man sein OS mal weitergeben möchte. :wink: Außerdem bist du dann an das gebunden was dieser Bootloader an Ausgabeformaten unterstützt. Der ist sicher nicht so flexibel wie grub.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #38 am: 03. May 2009, 12:57 »
Unter Vista gibt es doch auch einen Bootloader? (verwende selbst noch Win XP)
Soweit ich weiß, ist der Bootloader ziemlich der gleiche seit NT. Der kann allerdings auch nur Windows laden, oder chain loading, also eine Datei als Bootsektor in den Speicher nach 0x00007c00 laden.
Dieser Text wird unter jedem Beitrag angezeigt.

matheguru

  • Beiträge: 113
    • Profil anzeigen
Gespeichert
« Antwort #39 am: 04. May 2009, 14:45 »
Falls du das so meinst, dass erst der Vistabootloader chain loaden kann, liegst du falsch den das macht auch der NTLDR von NT-Systemen. Einfach einen Eintrag in der Boot.ini Datei, dabei muss sich der bootsector in einer datei auf der C-Partition im Haubtverzeichniss befinden: z.B. C:\BOOTSECT.DOS, wenn die Datei BOOTSECT.DOS heist.
Hacker zu sein bedeutet mehr, als sich nur damit auseinander zu setzen, es ist eine Lebenseinstellung

 

Einloggen