1

change the assembly to use push and pop

This commit is contained in:
2022-07-23 13:15:57 +02:00
parent 2d1c21584c
commit fe648cc49c

View File

@ -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