change the assembly to use push and pop
This commit is contained in:
@ -12,148 +12,245 @@
|
||||
;* Autor: Olaf Spinczyk, TU Dortmund *
|
||||
;*****************************************************************************
|
||||
|
||||
%include "kernel/threads/Thread.inc"
|
||||
|
||||
; EXPORTIERTE FUNKTIONEN
|
||||
|
||||
[GLOBAL Thread_switch]
|
||||
[GLOBAL Thread_start]
|
||||
|
||||
; TODO: Add function to unlock the scheduler again so I can use the spinlock
|
||||
|
||||
; 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;
|
||||
;; NOTE: New code with pusha/popa, restores all registers as I use this not only for first start
|
||||
;; == High address ==
|
||||
;; };
|
||||
;; *ESP
|
||||
;; SP --> RET ADDR
|
||||
;; == Low address ==
|
||||
|
||||
;; Load the contents of CoroutineState to the registers
|
||||
;; NOTE: I added all the registers saved in thread_state as I use it to switch to a new thread when the old thread
|
||||
;; was killed/exited before (so thread_state not available)
|
||||
mov esp, [esp + 0x4]
|
||||
;; == High address ==
|
||||
;; *OBJECT
|
||||
;; 0x13115
|
||||
;; *KICKOFF
|
||||
;; EAX
|
||||
;; ECX
|
||||
;; EDX
|
||||
;; EBX
|
||||
;; ESP
|
||||
;; EBP
|
||||
;; ESI
|
||||
;; EDI
|
||||
;; SP --> EFLAGS
|
||||
;; == Low address ==
|
||||
|
||||
mov ebx, [eax + efl_offset] ; restore eflags before restoring ebx
|
||||
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
|
||||
|
||||
;; The stackpointer now points to the coroutine stack
|
||||
;; struct CoroutineState {
|
||||
;; == High address ==
|
||||
;; *OBJECT
|
||||
;; 0x13115
|
||||
;; SP: *KICKOFF
|
||||
;; *OBJECT
|
||||
;; 0x13115
|
||||
;; *KICKOFF
|
||||
;; EAX
|
||||
;; ECX
|
||||
;; EDX
|
||||
;; EBX
|
||||
;; ESP
|
||||
;; EBP
|
||||
;; ESI
|
||||
;; SP --> EDI
|
||||
;; == Low address ==
|
||||
|
||||
popa
|
||||
;; == High address ==
|
||||
;; *OBJECT
|
||||
;; 0x13115
|
||||
;; SP --> *KICKOFF
|
||||
;; == Low address ==
|
||||
;; };
|
||||
|
||||
;; Reenable interrupts
|
||||
;; NOTE: I added this also to Thread_start as I use it to switch to a new thread when the old thread
|
||||
;; was killed/exited before (so thread_state not available)
|
||||
sti
|
||||
|
||||
;; 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
|
||||
|
||||
;; NOTE: New code with pusha/popa
|
||||
;; == High address ==
|
||||
;; *REGS_THEN
|
||||
;; *REGS_NOW
|
||||
;; *ESP_NEXT
|
||||
;; *ESP_PREV
|
||||
;; SP --> RET ADDR
|
||||
;; == Low address ==
|
||||
|
||||
push eax ; Backup eax
|
||||
;; == High address == ; Scheduler stack
|
||||
;; *ESP_NEXT
|
||||
;; + 0x8 *ESP_PREV
|
||||
;; RET ADDR
|
||||
;; SP --> EAX
|
||||
;; == Low address ==
|
||||
push eax ; backup eax before using it as index
|
||||
mov eax, [esp + 0x8] ; + 0x8 because we pushed eax
|
||||
|
||||
add esp, 0x4 ; store the original esp
|
||||
mov [eax + esp_offset], esp
|
||||
sub esp, 0x4
|
||||
mov eax, [esp + 0x8]
|
||||
;; == High address == ; Previous thread stack (thread that was running when the interrupt came)
|
||||
;; OLD
|
||||
;; THREAD
|
||||
;; STACK
|
||||
;; EAX -> RET ADDR
|
||||
;; == Low address ==
|
||||
|
||||
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
|
||||
sub eax, 0x28
|
||||
;; == High address ==
|
||||
;; OLD
|
||||
;; THREAD
|
||||
;; STACK
|
||||
;; 0x0 RET ADDR
|
||||
;; 0x4
|
||||
;; 0x8
|
||||
;; 0xc
|
||||
;; 0x10
|
||||
;; 0x14
|
||||
;; 0x18
|
||||
;; 0x1c
|
||||
;; 0x20
|
||||
;; 0x24
|
||||
;; EAX ->
|
||||
;; == Low address ==
|
||||
|
||||
pushf ; store eflags
|
||||
pop ebx ; ebx has to be saved before
|
||||
mov [eax + efl_offset], ebx
|
||||
mov [eax], esp ; Current esp to old thread stack, 0x24 is the amount pusha, pushf change the esp
|
||||
; We save it, push the current registers to the old threads stack, return and restore
|
||||
;; == High address ==
|
||||
;; OLD
|
||||
;; THREAD
|
||||
;; STACK
|
||||
;; 0x0 RET ADDR
|
||||
;; 0x4
|
||||
;; 0x8
|
||||
;; 0xc
|
||||
;; 0x10
|
||||
;; 0x14
|
||||
;; 0x18
|
||||
;; 0x1c
|
||||
;; 0x20
|
||||
;; 0x24
|
||||
;; EAX -> ESP (Points not to RET ADDR but the EAX we pushed as backup!!!)
|
||||
;; == Low address ==
|
||||
|
||||
pop ebx ; store eax
|
||||
mov [eax + eax_offset], ebx
|
||||
;; BUG: Not the correct value
|
||||
pop eax ; ESP still points to the EAX we pushed before
|
||||
;; == High address ==
|
||||
;; *ESP_NEXT
|
||||
;; *ESP_PREV
|
||||
;; SP --> RET ADDR
|
||||
;; == Low address ==
|
||||
|
||||
;; Load next coroutine registers ============================================================
|
||||
mov eax, [esp + 0x8] ; + 0x8 again since we popped eax value again
|
||||
mov esp, [esp + 0x4]
|
||||
;; == High address ==
|
||||
;; OLD
|
||||
;; THREAD
|
||||
;; STACK
|
||||
;; SP --> RET ADDR
|
||||
;; 0x4
|
||||
;; 0x8
|
||||
;; 0xc
|
||||
;; 0x10
|
||||
;; 0x14
|
||||
;; 0x18
|
||||
;; 0x1c
|
||||
;; 0x20
|
||||
;; 0x24
|
||||
;; 0x28 ESP
|
||||
;; == Low address ==
|
||||
|
||||
mov ebx, [eax + efl_offset] ; restore eflags before restoring ebx
|
||||
push ebx ; could be pushed directly from address but i didn't want to specify wordsize
|
||||
popf
|
||||
pusha ; Save current registers to stack
|
||||
;; == High address ==
|
||||
;; OLD
|
||||
;; THREAD
|
||||
;; STACK
|
||||
;; RET ADDR
|
||||
;; EAX
|
||||
;; ECX
|
||||
;; EDX
|
||||
;; EBX
|
||||
;; ESP
|
||||
;; EBP
|
||||
;; ESI
|
||||
;; EDI
|
||||
;; SP -->
|
||||
;; ESP
|
||||
;; == Low address ==
|
||||
|
||||
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
|
||||
pushf
|
||||
;; == High address ==
|
||||
;; OLD
|
||||
;; THREAD
|
||||
;; STACK
|
||||
;; RET ADDR
|
||||
;; EAX
|
||||
;; ECX
|
||||
;; EDX
|
||||
;; EBX
|
||||
;; ESP
|
||||
;; EBP
|
||||
;; ESI
|
||||
;; EDI
|
||||
;; EFLAGS
|
||||
;; SP --> ESP
|
||||
;; == Low address ==
|
||||
|
||||
pop esp ; The POP ESP instruction increments the stack pointer (ESP)
|
||||
; before data at the old top of stack is written into the destination.
|
||||
;; == High address ==
|
||||
;; *ESP_NEXT
|
||||
;; *ESP_PREV
|
||||
;; RET ADDR
|
||||
;; SP -->
|
||||
;; == Low address ==
|
||||
|
||||
mov esp, [esp + 0xc] ; Move to next coroutines stack
|
||||
;; == High address ==
|
||||
;; NEW
|
||||
;; THREAD
|
||||
;; STACK
|
||||
;; RET ADDR
|
||||
;; EAX
|
||||
;; ECX
|
||||
;; EDX
|
||||
;; EBX
|
||||
;; ESP
|
||||
;; EBP
|
||||
;; ESI
|
||||
;; EDI
|
||||
;; SP --> EFLAGS
|
||||
;; == Low address ==
|
||||
|
||||
popf ; Load new registers from stack
|
||||
;; == High address ==
|
||||
;; NEW
|
||||
;; THREAD
|
||||
;; STACK
|
||||
;; RET ADDR
|
||||
;; EAX
|
||||
;; ECX
|
||||
;; EDX
|
||||
;; EBX
|
||||
;; ESP
|
||||
;; EBP
|
||||
;; ESI
|
||||
;; SP --> EDI
|
||||
;; == Low address ==
|
||||
|
||||
popa
|
||||
;; == High address ==
|
||||
;; NEW
|
||||
;; THREAD
|
||||
;; STACK
|
||||
;; SP --> RET ADDR
|
||||
;; == Low address ==
|
||||
|
||||
;; 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
|
||||
|
Reference in New Issue
Block a user