;***************************************************************************** ;* * ;* C O R O U T I N E * ;* * ;*---------------------------------------------------------------------------* ;* Beschreibung: Assemblerdarstellung der 'struct CoroutineState' aus * ;* CoroutineState.h * ;* * ;* Die Reihenfolge der Registerbezeichnungen muss unbedingt * ;* mit der von 'struct CoroutineState' uebereinstimmen. * ;* * ;* Autor: Olaf Spinczyk, TU Dortmund * ;***************************************************************************** %include "kernel/threads/Thread.inc" ; EXPORTIERTE FUNKTIONEN [GLOBAL Thread_switch] [GLOBAL Thread_start] ; IMPLEMENTIERUNG DER FUNKTIONEN [SECTION .text] ; COROUTINE_START : Startet die erste Coroutine ueberhaupt. ; ; C Prototyp: void Coroutine_start (struct CoroutineState* regs); ;; Coroutine_start is called with one arg: CoroutineState* regs, so the main stack looks like this: ;; NOTE: Since this assembly is not generated by the compiler, there is no ebp prelude. ;; To address parameters we use esp. ;; == High address == ;; *REGS ;; ESP: RET ADDR ;; == Low address == Thread_start: ; * ; * Hier muss Code eingefuegt werden ; * ;; Set eax to the address where the CoroutineState struct is in memory: mov eax, [esp + 0x4] ;; Now eax points to the beginning of CoroutineState: ;; struct CoroutineState { ;; == Low address == ;; EAX: void *ebx; ;; void *esi; ;; void *edi; ;; void *ebp; ;; void *esp; ;; == High address == ;; }; ;; Load the contents of CoroutineState to the registers mov esp, [eax + esp_offset] ;; The stackpointer now points to the coroutine stack ;; struct CoroutineState { ;; == High address == ;; *OBJECT ;; 0x13115 ;; SP: *KICKOFF ;; == Low address == ;; }; ;; Return to kickoff ret ; COROUTINE_SWITCH : Coroutinenumschaltung. Der aktuelle Registersatz wird ; gesichert und der Registersatz der neuen Coroutine ; wird in den Prozessor eingelesen. ; ; C Prototyp: void Coroutine_switch (struct CoroutineState* regs_now, struct CoroutineState* reg_then); ; ; Achtung: Die Parameter werden von rechts nach links uebergeben. ; ;; == High address == ;; *REGS_THEN ;; *REGS_NOW ;; SP --> RET ADDR ;; == Low address == Thread_switch: ; * ; * Hier muss Code eingefuegt werden ; * ;; Save current coroutine registers ;; == High address == ;; *REGS_THEN ;; *REGS_NOW ;; RET ADDR ;; SP --> EAX ;; == Low address == push eax ; backup eax before using it as index mov eax, [esp + 0x8] add esp, 0x4 ; store the original esp mov [eax + esp_offset], esp sub esp, 0x4 mov [eax + ebx_offset], ebx ; store other regs mov [eax + esi_offset], esi mov [eax + edi_offset], edi mov [eax + ebp_offset], ebp mov [eax + ecx_offset], ecx mov [eax + edx_offset], edx pushf ; store eflags pop ebx mov [eax + efl_offset], ebx pop ebx ; store eax mov [eax + eax_offset], ebx ;; Load next coroutine registers ============================================================ mov eax, [esp + 0x8] mov ebx, [eax + efl_offset] ; restore eflags push ebx ; could be pushed directly from address but i didn't want to specify wordsize popf mov ebx, [eax + ebx_offset] ; restore other regs mov esi, [eax + esi_offset] mov edi, [eax + edi_offset] mov ebp, [eax + ebp_offset] mov esp, [eax + esp_offset] mov ecx, [eax + ecx_offset] mov edx, [eax + edx_offset] mov eax, [eax + eax_offset] ; restore eax ;; Enable interrupts again sti ;; NOTE: The stackpointer points to kickoff if the next coroutine was just initialized. ;; Otherwise it just points somewhere in the next coroutines stack ret