Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: ChristianF am 06. June 2008, 14:45

Titel: Multitasking
Beitrag von: ChristianF am 06. June 2008, 14:45
Ahoi
Ich habe da mal mehrere Fragen, wegen des Multitaskings. :-D
 
Also bis jetzt habe ich das so verstanden:
Es gibt einen Prozess, der erstellt wird, wenn z.B. ein Programm ausgeführt werden soll.
Dieser Prozess hat nun zur Ausführung Unterprozesse also Threads.

Mit dieser Aussage habe ich nun 2 Strukturen erstellt, einmal für einen Process und einmal für einen Thread.
typedef struct process
{
/* Process Stack */
unsigned int esp;
        /* Kernel Stack */
        unsigned int kernel_stack;
/* Process ID */
unsigned int pid;
/* Process Name */
char *process_name;
/* Page Directory */
page_directory_t cr3;
/* Lists with Threads from this process */
list_t *threads;
/* Max. Execution Time */
unsigned int timer_ticks_for_execution;
/* Execution time left */
unsigned int timer_ticks_left;
/* Stores the Process State */
unsigned int process_state;
} process_t;

typedef struct thread
{
/* Thread Stack */
unsigned int esp;
/* Thread Name */
char *thread_name;
/* stores the thread state */
unsigned int thread_state;
/* Is Thread in Virtual 8086 Mode */
bool is_vm8086;
} thread_t;

Nun muss ich einen Stack anlegen, wo der eip auf start gesetzt wird.
Ist die Struktur so vollständig oder fehlt da noch was, was unbedingt rein muss?
 
Bei den VM86 Tasks wollte ich den Code komplett über Threads ausführen lassen. Kann ich das so machen?
 
Brauche ich nur den einen Stack, weil ich meine wo anders gelesen zu haben, dass ich mehr als einen Stack brauche.  :-o
 
Gruß Christian
Titel: Re: Multitasking
Beitrag von: Termite am 06. June 2008, 15:24
Jede Task Thread oder auch Prozess braucht seinen eigenen Stack. sonst knallt das ganz böse.

Titel: Re: Multitasking
Beitrag von: ChristianF am 06. June 2008, 15:41
Mmmhhh...
Nun war aber noch in einem anderen Thread in dem Forum hier die Aussage, dass man neben dem Prozessstack nun auch den Kernelstack brauch.
 
So habe ich das zumindest in dem Code von Lost gesehen.
Dann würde ich gerne auf die TSS komplett verzichten. Geht das?
 
Sie hier: http://lowlevel.brainsware.org/forum/index.php?topic=1485.0
 
Gruß Christian
 
PS: Geplant ist momentan nur die kompatiblität zu 386er kompatiblen Prozessoren.
Titel: Re: Multitasking
Beitrag von: Korona am 06. June 2008, 16:22
Aufs TSS kannst du nicht verzichten, beim Wechsel Ring3 -> Ring0 wird SS und ESP aus dem TSS gelesen. Ohne TSS kriegst du da eine GPF.
Du brauchst für jeden Thread einen Usermode und einen Kernelstack. Sonst könnte es passieren dass beim Aufruf von Interrupts der Stack überläuft. Da wie gesagt beim Ringwechsel SS und ESP neu geladen werden ist es auch garnicht möglich nur einen Stack zu verwenden.

Ich würde mir aber nochmal überlegen, ob du deiner Prozessstruktur Felder für Stacks gibst. Ich würde eher Threads als "Tasks" (auch kein klar definierter Ausdruck aber mir fält kein besserer ein) betrachten und Prozesse als die Umgebung in der Threads laufen. Sprich: Nicht Prozesse werden gescheduled, sondern Threads und Prozesse fassen lediglich alle Threads eines Address-Spaces zusammen.
Titel: Re: Multitasking
Beitrag von: ChristianF am 08. June 2008, 20:46
Okay.
Das würde heißen, dass ich eine TSS für den Kernel einbaue, praktisch also eine struktur "tss_t", die dann mit den 2 Werten befüllt wird.

Des Weiteren brauche ich auch eine TSS für die VM8086 Tasks. Für diese hatte ich mir dass dann so geplant, dass ich einen Deskriptor in der GDT habe, den ich jedes mal nach belieben umbiegen, sollte der aktuelle Task ein Virtueller sein.
 
 
Nicht Prozesse werden gescheduled, sondern Threads und Prozesse fassen lediglich alle Threads eines Address-Spaces zusammen.
Mmmmhhhh....
Ich hatte würde jedem Task einen 4 GB Addressraum geben, ausgenommen der für den Kernel reservierte Platz, was also bedeutet, dass ich bei jedem Taskwechsel das cr3 Register neuladen muss, also so:
 

 
Da habe ich jetzt noch eine Frage:
Wie sieht dass dan im speziellen aus, wenn ich ein Programm starte, z.B. einen editor?

 
Gruß Christian
Titel: Re: Multitasking
Beitrag von: kevin am 08. June 2008, 20:52
Nicht Prozesse werden gescheduled, sondern Threads und Prozesse fassen lediglich alle Threads eines Address-Spaces zusammen.
Mmmmhhhh....
Ich hatte würde jedem Task einen 4 GB Addressraum geben, ausgenommen der für den Kernel reservierte Platz, was also bedeutet, dass ich bei jedem Taskwechsel das cr3 Register neuladen muss, also so:
Alle Threads eines Prozesses teilen sich einen Adressraum. Das ist mehr oder weniger die Definition eines Threads. cr3 wirst du natuerlich trotzdem neu laden muessen, wenn du nicht gerade zwischen Threads desselben Prozesses umschaltest.
Titel: Re: Multitasking
Beitrag von: Korona am 08. June 2008, 21:12
Des Weiteren brauche ich auch eine TSS für die VM8086 Tasks. Für diese hatte ich mir dass dann so geplant, dass ich einen Deskriptor in der GDT habe, den ich jedes mal nach belieben umbiegen, sollte der aktuelle Task ein Virtueller sein.
Ja, ein TSS reicht, du änderst dann einfach bei jedem Threadwechsel die ESP und SS Addressen.

Zitat
  • Taskwechsel beginnt
  • Kernel Page Directory laden
  • Neuen Task "suchen"
  • Page Directory des Tasks laden
  • Task starten
Wenn der Kernel in alle Prozesse gemappt ist entfällt der zweite Schritt. Cr3 Wechsel sind sehr teuer also solltest du den Kernel in alle Prozesse mappen.

Zitat
Da habe ich jetzt noch eine Frage:
Wie sieht dass dan im speziellen aus, wenn ich ein Programm starte, z.B. einen editor?
  • Task wird erstellt
  • Programm wird in eine freie Speicherstelle geladen
  • (und nun ?)
-> Virtuellen Adressraum erstellen
-> Auf der Programmdatei auslesen welche Speicherprogramme das Programm benutzt
-> Diese Speicherbereiche in den neuen Adressraum mappen und das Programm entsprechent dorthin laden
-> Einstiegspunkt aus der Datei lesen und neuen Thread erstellen mit diesem Einstiegspunkt als Startadresse
Titel: Re: Multitasking
Beitrag von: nooooooooos am 08. June 2008, 22:25
Ja und schlussendlich musst du den neuen Prozess noch in deine Liste eintragen, damit der Scheduler ihn das nächste Mal drannimmt...

Gruss
Noooooooooos
Titel: Re: Multitasking
Beitrag von: ChristianF am 09. June 2008, 09:14
Ok dann habe ich das so jetzt verstanden.
 
Nun habe ich mir eine Struktur für die TSS mit Hilfe der folgenden Quelle erstellt: Link (http://sandpile.org/ia32/tss.htm).
Danach habe ich eine Funktion geschrieben, die eine TSS initialisiert, und zwar in folgenden Schritten:
Nun sollte ich allerdings den Wert esp0 noch befüllen, doch mit was ???
Soll ich den aktuellen esp-Wert verwenden, oder irgendwie was anderes ???
 
Hier ist nochmal der Code, von dem oben erklärten:
typedef struct tss
{
unsigned short __blh, link;
unsigned int esp0;
unsigned short __ss0, ss0;
unsigned int esp1;
unsigned short __ss1, ss1;
unsigned int esp2;
unsigned short __ss2, ss2;
unsigned int cr3;
unsigned int eip;
unsigned int eflags;
unsigned int eax, ecx, edx, ebx;
unsigned int esp, ebp, esi, edi;
unsigned short __es, es;
unsigned short __ds, ds;
unsigned short __fs, fs;
unsigned short __gs, gs;
unsigned short __ldtr, ldtr;
} tss_t;

tss_t kernel_tss;
void load_kernel_tss(void)
{
gdt_set_gate(5, &kernel_tss, (&kernel_tss+sizeof(tss_t)), 0x89, 0xCF);
gdt_flush();

kernel_tss.ss0 = KERNEL_DATA_SEL;
// kernel_tss.esp0 =

LTR(5*0x8)
}
Anmerkung: LTR() ist ein Makro.
 
 
Gruß Christian
Titel: Re: Multitasking
Beitrag von: Korona am 09. June 2008, 13:40
Mit dem Stack der bei einem Interrupt benutzt werden soll (= dem Kernel Stack des jeweiligen Threads).
Für jeden Thread erstellst du einen Kernelthread und setzt vor jedem Taskwechsel den ESP Wert des TSS auf den Anfang des Kernelstacks des Threads der als nächstes laufen soll.
Titel: Re: Multitasking
Beitrag von: ChristianF am 09. June 2008, 14:04
Das würde heißen, dass dieser Stack nur Interrupts verarbeitet, z.B.: System Calls.
Folglich würde mein Stack, der in esp0 gespeichert wird, also so aussehen:
/* ToDo: Check value (4096) */
unsigned int *stack = kmalloc(4096)+4096;

*--stack = 0x0202; //EFLAGS
*--stack = 0x08;   //CS
*--stack = (unsigned int)interrupt_handler; //EIP
//'pusha'
*--stack = 0; //EDI
*--stack = 0; //ESI
*--stack = 0; //EBP
*--stack = 0; //Just an offset, no value
*--stack = 0; //EBX
*--stack = 0; //EDX
*--stack = 0; //ECX
*--stack = 0; //EAX
// data segments pushed by IRQ handler
*--stack = 0x10; //DS
*--stack = 0x10; //ES
*--stack = 0x10; //FS
*--stack = 0x10; //GS

Aber das kann doch nicht so einfach sein oder doch ???
 
 
Gruß Christian
Titel: Re: Multitasking
Beitrag von: bluecode am 09. June 2008, 16:51
Zu deiner Struktur tss: Du solltest evtl. dem Compiler mitteilen, dass er die Struktur nicht padden sollte, bei gcc geht das folgendermaßen:
struct foo
{
} __attribute__((packed));

Ich hab mir das Erstellen deines Kernelstacks jetzt nicht ìm Detail angesehen (Da gibts ja auch bei genug Hobby-OS Code dazu), aber jo, das funktioniert eigentlich schon so. Welche Probleme siehst du denn dabei?
Titel: Re: Multitasking
Beitrag von: ChristianF am 09. June 2008, 18:05
Ich sehe keine Probleme, nur manchmal denke ich um 10 Ecken und kann dann nicht glauben, dass es mit einer solch simplen Lösung getan ist
 :-D
Titel: Re: Multitasking
Beitrag von: ChristianF am 16. June 2008, 14:12
Ich habe da noch eine Konzeptionelle Frage:
Ist es sinnvoll Treiber-Tasks in Ring 0 laufen zulassen, oder sollte das doch besser Ring 3 sein?

Gruß Christian
Titel: Re: Multitasking
Beitrag von: bluecode am 16. June 2008, 16:48
Kommt drauf an ob man einen Microkernel oder einen monolithischen Kernel haben möchte. Beim Microkernel wären die Treiber in eigenen Prozessen (und damit in Ring3) bei einem monolithischen Kernel hingegen innerhalb des Kernels (und damit Ring 0).
Titel: Re: Multitasking
Beitrag von: ChristianF am 17. June 2008, 07:30
Nun ja....
ich versuche mich ja an einem Microkernel.
Würde ich die Treiber allerdings als Ring 3-Tasks laufen lassen, braucht die Struktur noch eine Menge Zusatz.
So müsste ich irgendwie standardmäßig den Portzugriff verhindern.
 
Des Weiteren habe ich noch eine Frage zur IPC. Durch das Shared Memory, könnten nur innerhalb des Tasksdie Threads untereinander kommunizieren, da der Speicher, der dafür verwendet wird anderswo vielleicht belegt ist...
Habe ich das so richtig verstanden?
Wenn ja, dann wäre das doch eigentlich recht sinnlos oder  :?
 
 
Gruß Christian
Titel: Re: Multitasking
Beitrag von: bluecode am 17. June 2008, 08:38
So müsste ich irgendwie standardmäßig den Portzugriff verhindern.
:? Der Portzugriff ist standardmäßig in Ring3 verboten, es sei denn du setzt das IOPL oder erstellst eine I/O Permission Bitmap.
 
Zitat
Des Weiteren habe ich noch eine Frage zur IPC. Durch das Shared Memory, könnten nur innerhalb des Tasksdie Threads untereinander kommunizieren, da der Speicher, der dafür verwendet wird anderswo vielleicht belegt ist...
Habe ich das so richtig verstanden?
Nein, das wäre natürlich Blödsinn. Der Speicher innerhalb eines Prozesses ist logischerweise immer zwischen den Threads geshared, zumindest wenn man vom klassischen Model eines Prozesses als Ressourcencontainer ausgeht. Man kann das natürlich wie immer auch anders machen, ob das Sinn macht ist dann natürlich wieder eine ganz andere Frage. Unter Threads des gleichen Prozesses ist es natürlich klar, dass der ges. Speicher geshared wird.
Wenn man das allerdings zwischen mehreren Prozessen machen will ist halt etwas mehr Aufwand notwendig, da wie du schon richtig bemerkt hast, man die Speicherseiten die geshared werden gesondert verwalten muss, damit sie nicht mehrfach bzw. zu früh freigegeben werden, etc... Wenn man das dann nun gesondert verwaltet, dann wird der Speicherbereich einfach irgendwo in die Adressräume der beiden Prozesse eingeblendet. Man muss logischerweise selbst für korrekte Synchronisation von Zugriffen sorgen. Man kann logischerweise auch keine Pointer über den shared-memory Bereich übergeben, da Pointer normalerweise nur innerhalb eines Prozesses gültig sind.
Titel: Re: Multitasking
Beitrag von: ChristianF am 27. June 2008, 09:10
Morgen

So müsste ich irgendwie standardmäßig den Portzugriff verhindern.
:? Der Portzugriff ist standardmäßig in Ring3 verboten, es sei denn du setzt das IOPL oder erstellst eine I/O Permission Bitmap.
ok.
 
Nun ist mir eben eine Idee gekommen :evil:
Also folgendes:
Ich habe einen Prozess/Task. Dieser hat einen stack, der einfach auf eine Funktion im Kernel zeigt, die dann zwischen den einzelnen Threads wechselt, also für jeden Task praktisch eine Funktion change_thread(..).

Ist das sinnvoll, also kann ich das verwenden?
So würde ich nämlich die Funktion zum wechseln des Tasks change_task(...) "entlasten".
 
Gruß Christian
 
PS: Die Funktionsnamen sind nur Beispiele.
Titel: Re: Multitasking
Beitrag von: bluecode am 27. June 2008, 15:18
Dein Kernel wird/sollte normalerweise (sobald du Paging aktivierst) als Supervisor gemappt sein, d.h. du hast mit Ring3 Code keinen Zugriff, weder lesen noch schreibend noch (und ganz besonders nicht) ausführend. Außerdem kannst du bestimmte Instruktionen, die bei einem Threadswitch interessant sind aus Ring3 Code nicht verwenden.
Deine verwendete Technik würde man übrigens cooperative multitasking nennen (zumindest so wie ich das jetzt von dir verstanden habe) und ist nicht sonderlich sinnvoll, da ein Thread dann durch "nicht-aufrufen" der Funktion das OS blockieren könnte.

Normalerweise wird man eben bei einem IRQ0 (also dem Timerinterrupt) oder anderen geeigneten Interrupts (zB HPET, Local APIC Timer, RTC Timer wenn man zu viel getrunken hat) machen oder aber ein Thread sagt von sich aus "ich hab keinen Bock mehr" durch einen Syscall, welcher dann diesen Thread blockiert (da er zB auf ein anderes Ereignis warten möchte) und zu einem anderen Thread wechselt. Syscalls werden meisten aber über spezielle Instruktionen (int n, syscall oder auch sysenter) implementiert und nicht über einen normalen Funktionsaufruf (siehe auch oben zur Begründung).

Ich hoffe ich konnte helfen. :-)
Titel: Re: Multitasking
Beitrag von: ChristianF am 30. June 2008, 10:18
Mmmhhh....
Eigentlich wollte ich ja preemptives Multitasking einsetzen. Aber deine Antwort hat auf jeden Fall geholfen.
 
Nun ist folgendes:
Ich möchte alle Tasks als 32-Bit Tasks aufrufen und dann, falls es nötig sein sollte 16-Bit Code auszuführen 16-Bit Threads erstellen. Daraus folgt dann, dass es keine 16-Bit Programme gibt.
 
Wie mache ich das aber dann, wenn ich irgendwann sowas wie z.B. *.com Programme ausführen möchte, also komplett 16-Bit?
Gibt es eine möglichkeit zu prüfen, ob ein Programm nun 16-Bit oder 32-Bit Code verwendet? Denn in dem Fall, vorrausgesetzt, dass das geht, würde ich dann auch wieder einen normalen 32-Bit Task erstellen, jedoch gleich mit einem VM8086-Thread.
 
Gruß Christian
Titel: Re: Multitasking
Beitrag von: bluecode am 30. June 2008, 17:13
Gibt es eine möglichkeit zu prüfen, ob ein Programm nun 16-Bit oder 32-Bit Code verwendet?
Das sagt dir das Dateiformat der ausführbaren Datei.
Titel: Re: Multitasking
Beitrag von: ChristianF am 01. July 2008, 16:40
Nun das funktioniert vllt. bei *.com und anderen 16-Bit Formaten.
Allerdings kann ich eine Datei Binär einmal 16-Bit und einmal 32-Bit compilieren, oder assemblieren, oder wie auch immer.
 
Aber das ist egal, denn das werde ich später noch herausfinden.
Titel: Re: Multitasking
Beitrag von: bluecode am 01. July 2008, 17:01
Nun das funktioniert vllt. bei *.com und anderen 16-Bit Formaten.
Allerdings kann ich eine Datei Binär einmal 16-Bit und einmal 32-Bit compilieren, oder assemblieren, oder wie auch immer.
Meinst du nicht, dass das ein von dir selbst verursachtes Problem ist? :wink: Ich mein exakt für solche Zusatzinformationen sind Dateiformate da. Wobei 16bit Code auch schon wieder so alt ist, dass es dafür kein ELF Dateiformat gibt. Ich seh auch nicht wirklich den Nutzen jetzt noch irgendwelchen 16bit Code ausführen zu wollen (einzige Ausnahme sind die VESA BIOS Extensions vllt.). Ich mein es wird demnächst sowieso Richtung EFI und logischerweise weg vom BIOS gehen...
Und rein vom Code her kann man das nicht praktikabel unterscheiden. Du könntest auch nicht praktikabel zwischen PowerPC, ARM und x86 Maschinencode unterscheiden (und das nicht weil die gleich wären :-D ).
Titel: Re: Multitasking
Beitrag von: kevin am 01. July 2008, 18:43
Nun das funktioniert vllt. bei *.com und anderen 16-Bit Formaten.
Allerdings kann ich eine Datei Binär einmal 16-Bit und einmal 32-Bit compilieren, oder assemblieren, oder wie auch immer.
Nur der Vollständigkeit halber: Die .com-Dateien von DOS sind einfach nur reiner Maschinencode ohne echtes Dateiformat, also flache Binaries. Womit du vielleicht eher was anfangen kannst, ist .exe. Aber nur vielleicht. ;)
Titel: Re: Multitasking
Beitrag von: MNemo am 01. July 2008, 18:54
mal so zur Anschauung
ein
[BITS 32]
mov eax, ebx
mov cx, dx
produziert exact den selben binärcode wie
[BITS 16]
mov ax, bx
mov ecx, edx
der unterschied besteht halt in der interpretation vom processor

Binärcode16Bit-CPU32Bit-CPU
0x89 0xd8mov ax, bxmov eax, ebx
0x66(Operand Size Prefix) 0x89 0xd8mov eax, ebxmov ax,bx
Titel: Re: Multitasking
Beitrag von: ChristianF am 04. July 2008, 08:09
Nun das funktioniert vllt. bei *.com und anderen 16-Bit Formaten.
Allerdings kann ich eine Datei Binär einmal 16-Bit und einmal 32-Bit compilieren, oder assemblieren, oder wie auch immer.
Nur der Vollständigkeit halber: Die .com-Dateien von DOS sind einfach nur reiner Maschinencode ohne echtes Dateiformat, also flache Binaries. Womit du vielleicht eher was anfangen kannst, ist .exe. Aber nur vielleicht. ;)
Kein Bedarf....  :-)

 
Ich habe mal über die ganze Interprozesskommunikation nachgedacht. Und zwar habe ich mir folgendes überlegt (basierend auf i386):

Ich ändere, bzw. erweitere meine Virtuelle Speicheraufteilung. Zuvor war der Aufbau wie folgt:
0x00000000 - 0xBFFFFFFF     => User Programme
0xC0000000 - 0xCFFFFFFF     => Kernel
0xD0000000 - 0xDFFFFFFF     => Kernel Heap
0xE0000000 - 0xFFFFFFFF     => "Noch nicht vergeben"
Geändert sieht das nun So aus:
0x00000000 - 0xBFFFFFFF     => User Programme
0xC0000000 - 0xCFFFFFFF     => Kernel
0xD0000000 - 0xD000FFFF     => Kernel Heap
0xD0010000 - 0xDFFFFFFF     => Multitasking (Task Stacks, Thread Stacks, ...)
0xE0000000 - 0xFFFFFFFF     => Platz für IPC (Shared Memory, Message Passing, ...)

Was meint ihr dazu?
Seht ihr irgendwelche Nachteile, oder ähnliches?
 
 
Gruß Christian
 
PS: Den Kram mit der Unterscheidung von 16 und 32 Bit habe ich jetzt einfach mal nach hinten verschoben :D
Titel: Re: Multitasking
Beitrag von: bluecode am 04. July 2008, 15:15
Was meint ihr dazu?
Seht ihr irgendwelche Nachteile, oder ähnliches?
Wenn du den Kernel Heap direkt hinter den Kernel klebst, dann ist für den Heap ein bisschen mehr Platz :wink: Ich würde sagen 0x10000 ist ein bisschen wenig für den Kernel Heap. Zumindest ist für die Kernel Binary überproportional viel Platz (Ich hab jetzt einfach mal das 'Kernel' in deiner Liste als das Kernel image bzw. die Binary interpretiert).
Ansonsten steht da nicht wirklich was konkretes, insofern lässt sich da nicht viel zu sagen...
Titel: Re: Multitasking
Beitrag von: jgraef am 04. July 2008, 15:43
Hi,

Der Heap ist etwas zu klein. Und außerdem würde ich die Task/Thread-Daten, IPC-Daten und sämtliche andere Daten des Kernels in den Kernelheap reinmachen, denn dafür ist er ja da.
Titel: Re: Multitasking
Beitrag von: bluecode am 04. July 2008, 16:39
Und außerdem würde ich die Task/Thread-Daten, IPC-Daten [...]
Das würde ich dann eher im Einzelfall nochmal betrachten, va. bei IPC halte ich das für sehr implementationsabhängig, zB wäre es bei shared-memory Schwachsinn, das auf einem Kernel Heap zu machen und selbst bei [fixed-size] message passing man vielleicht einen spezielleren Allokator (als malloc), da man da bestimmt einiges rausholen könnte, da man ja weiß wie die Allokationsgröße ist.
Titel: Re: Multitasking
Beitrag von: ChristianF am 12. August 2008, 13:11
Hmmm...
Mir stellt sich da gerade eine Frage...
 
Ich erkläre das mal an einem Beispiel:
Ich habe einen Grafiktreiber. Dieser wird jetzt gestartet.
Als erstes wird der Prozess mit einem Thread erstellt. Danach erstellt der Prozess
von sich aus einen neuen Thread, und zwar einen VM8086-Thread. Dieser wechselt
nun den Grafikmodus (VESA 1.0 oder so) und stirbt dann.

Da sich in einem Prozess ja die Threads die Resourcen teilen müsste ich ja auch auf
die Daten des gestorbenen Threads zugreifen können oder werden diese danach freigegeben?
 
Und noch eine Frage ist da. Ich bin momentan dabei Paging einzubauen.
Nun fordert ein Prozess per System Call Speicher an.
Nach welchen Kriterien mappt ihr den Physikalischen Speicher an welche Adresse?
Ist mir das frei gestellt, oder muss ich da irgendwas beachten?
 
Gruß Christian
 
 
*EDIT*
Mir ist klar, dass bei einem VM8086-Thread die physikalische Adresse innerhalb des ersten MBs sein muss.
Aber wie ist das bei normalen Prozessen, also elf oder flat binary?
Gibt es hier Informationen dazu im Header (zumindest bei elf)?

*EDIT2*
Es sieht so aus, als ob im ELF-Format eine virtuelle adresse gespeichert werden kann, aber nicht muss.
Diese wird mit dem Linker Skript festgelegt, bsp.: . = 0xA0000000 o.ä.
Da diese jedoch 0 sein kann, müsste ich ja praktisch eine Default Adresse festlegen, bsp.: ab 0x00100000.
Wie macht ihr das mit dem flat binary Format?
Titel: Re: Multitasking
Beitrag von: kevin am 12. August 2008, 15:09
Und noch eine Frage ist da. Ich bin momentan dabei Paging einzubauen.
Nun fordert ein Prozess per System Call Speicher an.
Nach welchen Kriterien mappt ihr den Physikalischen Speicher an welche Adresse?
Ist mir das frei gestellt, oder muss ich da irgendwas beachten?
Du schreibst das OS, dir ist alles freigestellt. Du kannst höchstens fragen, was für die Programme am sinnvollsten/bequemsten ist. Wenn in LOST Speicher angefordert wird, wird (irgendein) freier physischer Speicher gesucht und an (irgend)eine freie Stelle im virtuellen Speicher des Prozesses gemappt. Die virtuelle Adresse wird dann halt an den Prozeß zurückgegeben.
Titel: Re: Multitasking
Beitrag von: ChristianF am 13. August 2008, 08:11
Und noch eine Frage ist da. Ich bin momentan dabei Paging einzubauen.
Nun fordert ein Prozess per System Call Speicher an.
Nach welchen Kriterien mappt ihr den Physikalischen Speicher an welche Adresse?
Ist mir das frei gestellt, oder muss ich da irgendwas beachten?
Du schreibst das OS, dir ist alles freigestellt. Du kannst höchstens fragen, was für die Programme am sinnvollsten/bequemsten ist. Wenn in LOST Speicher angefordert wird, wird (irgendein) freier physischer Speicher gesucht und an (irgend)eine freie Stelle im virtuellen Speicher des Prozesses gemappt. Die virtuelle Adresse wird dann halt an den Prozeß zurückgegeben.
Nun, dass irgendeine freie physikalische Page verwendet wird, ist mir klar, die verwalte ich ja in einer Bitmap und in einem Stack.
Aber so wie das aussieht, muss ich mir wohl noch mal Gedanken machen, wie ich den Speicher bei normalen Anwendungen aufteile...
Mal schauen, vielleicht will mir was passendes dazu einfallen :D
 
Gruß Christian
Titel: Re: Multitasking
Beitrag von: bluecode am 14. August 2008, 12:05
Mir ist klar, dass bei einem VM8086-Thread die physikalische Adresse innerhalb des ersten MBs sein muss.
Im VM8086 ist Paging aktiviert. Insofern muss die virtuelle Adresse unter 1MB sein, nicht (unbedingt) die physikalische. Wobei natürlich klar sein sollte, dass man das BIOS und solche Sachen mappen muss/sollte.

Zitat
Wie macht ihr das mit dem flat binary Format?
In flat binary würden die meisten aber auch eine Header mit eben solchen Informationen einbauen. Ansonsten gilt: Du hast es gelinkt, dann musst du auch wissen wo was in der Datei gelandet ist und wo es hingeladen werden soll. Wenn du ELF bereits hast/willst, dann ist es imho Schwachsinn Unterstützung für Flat Binary einzubauen.
Titel: Re: Multitasking
Beitrag von: ChristianF am 14. August 2008, 14:16
Mir ist klar, dass bei einem VM8086-Thread die physikalische Adresse innerhalb des ersten MBs sein muss.
Im VM8086 ist Paging aktiviert. Insofern muss die virtuelle Adresse unter 1MB sein, nicht (unbedingt) die physikalische. Wobei natürlich klar sein sollte, dass man das BIOS und solche Sachen mappen muss/sollte.
Ups...
Da ist mir wohl ein Fehler unterlaufen ich meinte natürlich die virtuelle Adresse.
 
Zitat
Wie macht ihr das mit dem flat binary Format?
In flat binary würden die meisten aber auch eine Header mit eben solchen Informationen einbauen. Ansonsten gilt: Du hast es gelinkt, dann musst du auch wissen wo was in der Datei gelandet ist und wo es hingeladen werden soll. Wenn du ELF bereits hast/willst, dann ist es imho Schwachsinn Unterstützung für Flat Binary einzubauen.
Das macht auch irgendwo sinn.
Dann werde ich elf benutzen, und vllt. noch .exe, insofern es sich um keine Win32 Anwendung handelt.  :-P
 
*EDIT*
@bluecode
Nach welchem Schema wird denn bei Pedigree der Speicher gemappt?
Titel: Re: Multitasking
Beitrag von: ChristianF am 20. August 2008, 13:28
Hallo
 
Ich habe da noch etwas gefunden  :evil:
 
Ich habe aus interesse mir mal den LOST Quellcode angeschaut. Hier ist es gang und gebe, für jeden einzelnen Real Mode Interrupt ein VM86-Thread zu erstellen.
Diese Vorgehensweise habe ich nach einiger Zeit der Suche auch bei anderen Hobby Betriebssystemen gefunden.
 
In gewisser Hinsicht ist diese Implementation aber doch sehr langsam oder nicht?
Ein kleines Beispiel zur Verdeutlichung:
Ich habe ein Programm geschrieben, das einen 16 Bit Thread startet. Dieses macht einige movs, interrupts, usw!
 
Würde man solch ein Programm mit der obigen Implementation ausführen, wäre das ja ewig langsam, da wegen jeder Aktion ein extra Thread erstellt wird.
 
Oder ich habe etwas falsch verstanden, was aber möglich ist, ist das mischen von 16 und 32 Bit Code.
Der Aufruf einer Funktion zum initialisieren des Grafikmodus (VESA) würde dann auch ewig brauchen, was nicht meine Intention ist.
 
Wie sieht das sonst so aus? Wie regelt ihr das?
 
Gruß Christian
 
*EDIT*
Ich möchte keinen Quellcode sehen  :wink:
Titel: Re: Multitasking
Beitrag von: bluecode am 20. August 2008, 13:51
Ich biete in lightOS nicht die Möglichkeit 16bit Tasks zu erstellen, sondern ausschließlich einen Wrapper um VBE (innerhalb des Kernels). Ich wüsste so ad hoc auch nicht, was man damit sonst sinnvolles (!) anstellen könnte.
Titel: Re: Multitasking
Beitrag von: kevin am 20. August 2008, 15:17
Würde man solch ein Programm mit der obigen Implementation ausführen, wäre das ja ewig langsam, da wegen jeder Aktion ein extra Thread erstellt wird.
Ja, in der Tat, und dafür ist es auch nicht gedacht. Der typische Anwendungsfall ist der Aufruf eines BIOS-Interrupts zum Einschalten des Grafikmodus und vielleicht noch irgendwann ein zweiter, um wieder in den Textmodus zurückzuschalten. Da tut die Performance nicht wirklich weh.
 
Zitat von: bluecode
atok
Meinst du "ad hoc"? ;)
Titel: Re: Multitasking
Beitrag von: bluecode am 20. August 2008, 15:46
Zitat von: bluecode
atok
Meinst du "ad hoc"? ;)
steht doch da :-P :-D :oops:
Titel: Re: Multitasking
Beitrag von: ChristianF am 20. August 2008, 20:09
Nun ja mir ist jetzt aber auch kein anderes Beispiel eingefallen als der Grafikmodus...
Bzw. das ist das einzigst Sinnvolle beispiel, denn wer greift über RM Interrupts auf die Festplatte oder Diskette zu, wenn es dafür DMA gibt :-D
 
Aber wenn ich da richtig liege, wird der RM auch nur dafür gebraucht  :-D
Und auch unter Windows gibt es eine Möglichkeit, einen Interrupt einzeln auszuführen, z.B. beim setzen des Mode 13h.  :roll:
 
Mal schauen, wie es dann letzten endes aussehen wird, da ich noch nicht ganz mit der Speicherverwaltung fertig bin.
 
Grüße Christian
Titel: Re: Multitasking
Beitrag von: ChristianF am 04. February 2009, 08:37
So, da melde ich mich mal wieder...
 
Ich bin mit dem Multitasking nun soweit, dass ich Prozesse mit einzelnen Unterprozesse (Threads) erstellen und im "Round Robin"-Verfahren ausführen kann. So weit funktioniert auch alles, nur bin ich momentan am überlegen, wie ich das mit dem Page Directory und den User-Space Prozessen mache...
 
Momentan werden die Prozessstruktur und alles benötigte auf dem Kernel Heap abgelegt, der allerdings vom User-Space nicht erreichbar ist. Des Weiteren wird der Stack der einzelnen Threads im virtuellen Bereich 0xF0000000 - 0xFFFFF000 abgelegt.
 
Bezogen auf den User-Space müsste ich also folgende änderungen machen:
So müsste ich dann zum einen im Page Directory des Kernels die Thread-Stacks der Prozesse ablegen, sowie auch im Page Directory des Prozesses. Wohlgemerkt nur die Thread-Stacks, die der Prozess auch hat, denn die anderen da noch hinein zu mappen wäre nicht sehr sinnvoll.
 
Was ist eure Meinung zu diesem Text? Gibt es noch Punkte, die ich nicht berücksichtigt habe oder die überflüssig sind?
 
Gruß Christian
Titel: Re: Multitasking
Beitrag von: ChristianF am 17. August 2009, 08:19
Ich bin so langsam dabei, zu beginnen, den ganzen sinnlosen Krempel zu entfernen. Das heißt, dass ich den Code etwas aufräume...
 
Hierzu bin ich momentan beim Multitasking und beim Paging dran. Multitasking deswegen, weil ich bei dem Erstellen des Tasks immer das Page Directory kopiere, dann zu diesem wechsle und dann die Stacks (User-, TSS- und Kernelstack) mappe und mit Werten belege.
Dieses Unterfangen ist gelinde gesagt doof, weswegen ich angefangen habe, eine Funktion zu schreiben, die den Speicher auch dann mappt, wenn das gegebene Page Directory gerade nicht aktuell ist...
 
Hier habe ich mir auch nochmals den Code von Tyndur angeschaut, wobei mir aufgefallen ist, dass nur der User-Stack in das neue Page Directory gemappt wird. Der Kernelstack hingegen wird einfach im Page Directory des Kernels gemappt und initialisiert.
 
Ist es sinnvoll, den Kernelstack immer im Page Directory des Kernels abzulegen, oder sollte ich dabei bleiben, die Stacks immer in das für den Task erstellte Page Directory zu mappen?
 
Gruß Christian
Titel: Re: Multitasking
Beitrag von: kevin am 17. August 2009, 19:54
In erster Linie sollte der Stack in dem Page Directory sein, das aktiv ist, wenn er benutzt wird. ;)

Für tyndur ist es so, dass das erste GB in allen Speicherkontexten gleich ist.  Das heißt, wenn es eine Änderung an den Kernelmappings für ein PD gibt, wird diese Änderung auch in alle anderen PDs übertragen. Deswegen ist es das einfachste, den aktuellen Kontext herzunehmen.
Titel: Re: Multitasking
Beitrag von: ChristianF am 18. August 2009, 08:19
Das macht natürlich einiges einfacher...
 
Mal sehen...
Ich muss auch noch genau festlegen, wo die User-Programme/Treiber liegen und was Part des Kernels ist. Eventuell würde es bei mir so aussehen, dass 0-1 GB und GB 3 - 4 (0xCXXXXXXX) Bereiche des Kernels sind.
Titel: Re: Multitasking
Beitrag von: kevin am 18. August 2009, 09:20
Wozu willst du denn den Kernelspeicher auseinanderreißen?
Titel: Re: Multitasking
Beitrag von: ChristianF am 18. August 2009, 10:01
Mmmmmhhh...
In 0xCXXXXXXX liegt der Heap des Kernels...
Das hatte ich aus irgendeinem Tutorial mal übernommen und nach dem Neuschreiben des Heapmanagers nicht geändert.
Es wäre vielleicht sogar einfacher für das Zuordnen der Speicherseiten, wenn ich den Heap nach 0xAXXXXXXX verlegen würde und alle User-Programme ab 0xB0000000 zur Verfügung stellen würde...
 
Mal sehen, wie ich das dann letzten endes mache...
 
Noch eine Frage. Ich habe vor, nur einen einzigen Virtual 8086 Mode-Task maximal auszuführen. Das Programm führt also einen System Call aus und teilt mir mit, das der Interrupt 0x13 mit den Parametern xyz ausgeführt werden soll. Dafür erstelle ich einen Stack, sperre alle anderen Tasks für die Ausführungszeit, und führe diesen erstellten Task aus.
Meine Frage ist nun, muss ich dafür noch zusätzlich Speicher reservieren, außer für den Stack? Die Speicherseite < 1MB würde ich einfach für die Zeit der Ausführung des Interrupts in den Usermode mappen.