| Zeile 5: | Zeile 5: | ||
=== Das Task State Segment === | === Das Task State Segment === | ||
| − | Hardware-Multitasking beruht auf dem sogenannten Task State Segment, welches jedem Task zugeordnet wird und unter anderem dessen Registerwerte speichert. Der Aufbau des TSS wird [[TSS|hier exakt]] beschrieben | + | Hardware-Multitasking beruht auf dem sogenannten Task State Segment, welches jedem Task zugeordnet wird und unter anderem dessen Registerwerte speichert. Der Aufbau des TSS wird [[TSS|hier exakt]] beschrieben. |
| − | |||
| − | |||
| − | Der Speicherort des TSS wird als Eintrag in der GDT gespeichert. Der Selektor dieses Eintrags wird im Task Register der CPU gespeichert, wodurch sie bei einem Taskwechsel weiß, wo die (dynamischen) Registerwerte gespeichert werden sollen, damit diese beim Wiederaufruf des Tasks unverändert sind. Folgender Code legt ein TSS an und erzeugt dann den Descriptor in der GDT, der darauf zeigt. | + | Der Speicherort des TSS wird als Eintrag in der GDT gespeichert. Der Selektor dieses Eintrags wird im Task Register der CPU gespeichert, wodurch sie bei einem Taskwechsel weiß, wo die (dynamischen) Registerwerte gespeichert werden sollen, damit diese beim Wiederaufruf des Tasks unverändert sind. |
| + | |||
| + | Folgender Code legt ein TSS an und erzeugt dann den Descriptor in der GDT, der darauf zeigt. | ||
<c> | <c> | ||
| Zeile 135: | Zeile 135: | ||
Dieses doch recht kleine Codestück wird das eigentliche Multitasking übernehmen. | Dieses doch recht kleine Codestück wird das eigentliche Multitasking übernehmen. | ||
| − | Ich gehe dabei davon aus, dass in deinem OS bereits PIT und PIC initalisiert worden sind, denn | + | Ich gehe dabei davon aus, dass in deinem OS bereits PIT und PIC initalisiert worden sind, denn in der [[ISR]] des [[PIT|PITs]] wird der Schedulercode ausgeführt. |
| + | |||
Dafür muss er ersteinmal den nächsten Eintrag in der Task-Table finden, der aktiv ist (present-Feld ist nicht null) | Dafür muss er ersteinmal den nächsten Eintrag in der Task-Table finden, der aktiv ist (present-Feld ist nicht null) | ||
<c> | <c> | ||
DWORD current_task_id=0; | DWORD current_task_id=0; | ||
| − | + | WORD tss_sel; | |
| − | void | + | void scheduler() |
{ | { | ||
current_task_id++; | current_task_id++; | ||
| Zeile 149: | Zeile 150: | ||
if (current_task_id = NUM_TASKS]) current_task_id=0; | if (current_task_id = NUM_TASKS]) current_task_id=0; | ||
} | } | ||
| − | + | tss_sel = current_task_id + TSS_SEL_BASE; | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
</c> | </c> | ||
| − | + | Jetzt muss zu diesem Task geswechselt werden, indem zu dessen TSS-Selektor gesprungen wird. Es empfiehlt sich diesen Teil in Assembler zu schreiben, da die ISR auch aus einem Assemblerstub heraus aufgerufen werden sollte. Dieser sieht dann so aus: | |
| − | + | ||
| + | <asm> | ||
| + | extern _tss_sel | ||
| + | extern _scheduler | ||
| + | global _isr_pit | ||
| + | _isr_pit: | ||
| + | pusha | ||
| + | call _scheduler | ||
| + | mov ax, [_tss_sel] | ||
| + | mov [opcode_hack+5], ax | ||
| + | popa | ||
| + | opcode_hack: | ||
| + | jmp 1234 : 1234 | ||
| + | iret | ||
| + | </asm> | ||
| + | |||
| + | Jetzt musst du nur noch "isr_pit" in deine IDT als PIT Interrupthandler eintragen, damit der Scheduler auch bei jedem Tick aufgerufen wird und zum nächsten Task wechselt. | ||
=== Schritt 5: Multitasking initalisieren === | === Schritt 5: Multitasking initalisieren === | ||