change the assembly to use push and pop
This commit is contained in:
@ -12,148 +12,245 @@
|
|||||||
;* Autor: Olaf Spinczyk, TU Dortmund *
|
;* Autor: Olaf Spinczyk, TU Dortmund *
|
||||||
;*****************************************************************************
|
;*****************************************************************************
|
||||||
|
|
||||||
%include "kernel/threads/Thread.inc"
|
|
||||||
|
|
||||||
; EXPORTIERTE FUNKTIONEN
|
; EXPORTIERTE FUNKTIONEN
|
||||||
|
|
||||||
[GLOBAL Thread_switch]
|
[GLOBAL Thread_switch]
|
||||||
[GLOBAL Thread_start]
|
[GLOBAL Thread_start]
|
||||||
|
|
||||||
; TODO: Add function to unlock the scheduler again so I can use the spinlock
|
|
||||||
|
|
||||||
; IMPLEMENTIERUNG DER FUNKTIONEN
|
; IMPLEMENTIERUNG DER FUNKTIONEN
|
||||||
|
|
||||||
[SECTION .text]
|
[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:
|
Thread_start:
|
||||||
; *
|
; *
|
||||||
; * Hier muss Code eingefuegt werden
|
; * Hier muss Code eingefuegt werden
|
||||||
; *
|
; *
|
||||||
|
|
||||||
;; Set eax to the address where the CoroutineState struct is in memory:
|
;; NOTE: New code with pusha/popa, restores all registers as I use this not only for first start
|
||||||
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 ==
|
;; == High address ==
|
||||||
;; };
|
;; *ESP
|
||||||
|
;; SP --> RET ADDR
|
||||||
|
;; == Low address ==
|
||||||
|
|
||||||
;; Load the contents of CoroutineState to the registers
|
mov esp, [esp + 0x4]
|
||||||
;; NOTE: I added all the registers saved in thread_state as I use it to switch to a new thread when the old thread
|
;; == High address ==
|
||||||
;; was killed/exited before (so thread_state not available)
|
;; *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
|
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 ==
|
;; == High address ==
|
||||||
;; *OBJECT
|
;; *OBJECT
|
||||||
;; 0x13115
|
;; 0x13115
|
||||||
;; SP: *KICKOFF
|
;; *KICKOFF
|
||||||
|
;; EAX
|
||||||
|
;; ECX
|
||||||
|
;; EDX
|
||||||
|
;; EBX
|
||||||
|
;; ESP
|
||||||
|
;; EBP
|
||||||
|
;; ESI
|
||||||
|
;; SP --> EDI
|
||||||
|
;; == Low address ==
|
||||||
|
|
||||||
|
popa
|
||||||
|
;; == High address ==
|
||||||
|
;; *OBJECT
|
||||||
|
;; 0x13115
|
||||||
|
;; SP --> *KICKOFF
|
||||||
;; == Low address ==
|
;; == 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
|
sti
|
||||||
|
|
||||||
;; Return to kickoff
|
|
||||||
ret
|
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:
|
Thread_switch:
|
||||||
; *
|
; *
|
||||||
; * Hier muss Code eingefuegt werden
|
; * Hier muss Code eingefuegt werden
|
||||||
; *
|
; *
|
||||||
;; Save current coroutine registers
|
|
||||||
|
;; NOTE: New code with pusha/popa
|
||||||
;; == High address ==
|
;; == High address ==
|
||||||
;; *REGS_THEN
|
;; *ESP_NEXT
|
||||||
;; *REGS_NOW
|
;; *ESP_PREV
|
||||||
|
;; SP --> RET ADDR
|
||||||
|
;; == Low address ==
|
||||||
|
|
||||||
|
push eax ; Backup eax
|
||||||
|
;; == High address == ; Scheduler stack
|
||||||
|
;; *ESP_NEXT
|
||||||
|
;; + 0x8 *ESP_PREV
|
||||||
;; RET ADDR
|
;; RET ADDR
|
||||||
;; SP --> EAX
|
;; SP --> EAX
|
||||||
;; == Low address ==
|
;; == 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 + 0x8]
|
||||||
mov [eax + esp_offset], esp
|
;; == High address == ; Previous thread stack (thread that was running when the interrupt came)
|
||||||
sub esp, 0x4
|
;; OLD
|
||||||
|
;; THREAD
|
||||||
|
;; STACK
|
||||||
|
;; EAX -> RET ADDR
|
||||||
|
;; == Low address ==
|
||||||
|
|
||||||
mov [eax + ebx_offset], ebx ; store other regs
|
sub eax, 0x28
|
||||||
mov [eax + esi_offset], esi
|
;; == High address ==
|
||||||
mov [eax + edi_offset], edi
|
;; OLD
|
||||||
mov [eax + ebp_offset], ebp
|
;; THREAD
|
||||||
mov [eax + ecx_offset], ecx
|
;; STACK
|
||||||
mov [eax + edx_offset], edx
|
;; 0x0 RET ADDR
|
||||||
|
;; 0x4
|
||||||
|
;; 0x8
|
||||||
|
;; 0xc
|
||||||
|
;; 0x10
|
||||||
|
;; 0x14
|
||||||
|
;; 0x18
|
||||||
|
;; 0x1c
|
||||||
|
;; 0x20
|
||||||
|
;; 0x24
|
||||||
|
;; EAX ->
|
||||||
|
;; == Low address ==
|
||||||
|
|
||||||
pushf ; store eflags
|
mov [eax], esp ; Current esp to old thread stack, 0x24 is the amount pusha, pushf change the esp
|
||||||
pop ebx ; ebx has to be saved before
|
; We save it, push the current registers to the old threads stack, return and restore
|
||||||
mov [eax + efl_offset], ebx
|
;; == 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
|
;; BUG: Not the correct value
|
||||||
mov [eax + eax_offset], ebx
|
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 esp, [esp + 0x4]
|
||||||
mov eax, [esp + 0x8] ; + 0x8 again since we popped eax value again
|
;; == 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
|
pusha ; Save current registers to stack
|
||||||
push ebx ; could be pushed directly from address but i didn't want to specify wordsize
|
;; == High address ==
|
||||||
popf
|
;; 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
|
pushf
|
||||||
mov esi, [eax + esi_offset]
|
;; == High address ==
|
||||||
mov edi, [eax + edi_offset]
|
;; OLD
|
||||||
mov ebp, [eax + ebp_offset]
|
;; THREAD
|
||||||
mov esp, [eax + esp_offset]
|
;; STACK
|
||||||
mov ecx, [eax + ecx_offset]
|
;; RET ADDR
|
||||||
mov edx, [eax + edx_offset]
|
;; EAX
|
||||||
mov eax, [eax + eax_offset] ; restore 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
|
;; Enable interrupts again
|
||||||
sti
|
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
|
ret
|
||||||
|
|||||||
Reference in New Issue
Block a user